在列表/数组范围之外为零

时间:2013-11-26 13:02:12

标签: python arrays list numpy scipy

使用Python列表

L=[1,2,3,4]

如果L[m] = 0m不同,我希望0,1,2,3,即:

...
L[-2]=0 
L[-1]=0  
L[0]=1
L[1]=2
L[2]=3
L[3]=4
L[4]=0
L[5]=0

L[-2:2] = [0, 0, 1, 2]

这不适用于经典列表或数组。这样做的好方法是什么?

编辑:这是一个很好的解决方案(由一个答案给出):

class MyList(list):
    def __getitem__(self, index):
        return super(MyList, self).__getitem__(index) if index >= 0 and index < len(self) else 0

但我仍然无法拥有

L[-2:2] = [0, 0, 1, 2]

6 个答案:

答案 0 :(得分:6)

您可以将L转换为dict:

In [1]: L=[1,2,3,4]

In [2]: D=dict([(x, y) for x, y in enumerate(L)])

In [3]: [D.get(i, 0) for i in xrange(-3, 5)]
Out[3]: [0, 0, 0, 1, 2, 3, 4, 0]

答案 1 :(得分:1)

解决问题之一是声明你自己的get函数

def get(l, p):
   try:
       return l[p]
   except IndexError:
       return 0

ofc最后一行可以是l.append(0)或其他

答案 2 :(得分:1)

您可以使用特殊的get函数:

def get(l, p):
    return l[p] if p >= 0 and p < len(l) else 0

甚至覆盖__getitem__方法:

class MyList(list):
    def __getitem__(self, index):
        return super(MyList, self).__getitem__(index) if index >= 0 and index < len(self) else 0

示例:

>>> l2 = MyList([3, 5, 6, 8])
>>> l2[-1]
0
>>> l2[5]
0
>>> l2[2]
6

答案 3 :(得分:1)

您可以将内置列表子类化为在访问列表项时提供默认值:

class MyList(list):
    def __getitem__(self, item):
        if isinstance(item, slice):
            step = item.step if item.step else 1
            return [self.__getitem__(i) for i in xrange(item.start, item.stop, step)]
        try:
            value = super(MyList, self).__getitem__(item)
        except IndexError:
            value = 0
        return value

    def __getslice__(self, start, stop):
        return self.__getitem__(slice(start, stop, None))

使用示例:

>> L = MyList([1,2,3,4])
>> L[0]
1
>> L[1]
2
>> L[2]
3
>> L[3]
4
>> L[4]
0
>> L[5]
0
>> L[0:6]
[1, 2, 3, 4, 0, 0]

信用转到How to override the slice functionality of list in its derived class

答案 4 :(得分:1)

您可以使用slice个对象,这些对象在使用“扩展切片”时不会传递给__getslice__,而是传递给__getitem__。然后,将切片的start移至0,将stop移至len - 1,同时保持跟踪。然后添加零:

class MyList(list):
    def __getitem__(self, item):
        if isinstance(item, slice):
            s, e = item.start, item.stop
            l = len(self) - 1
            left = -s if s < 0 else 0
            s = max(s, 0)
            right = e - l if e > l else 0
            e = min(e, l)
            return [0]*left + super(MyList, self).__getitem__(slice(s,e,item.step)) + [0]*right
        elif item < 0 or item >= len(self):
            return 0
        else:
            return super(MyList, self).__getitem__(item)

问题是:您必须强制getslice调用以发送slice对象,您可以通过以下两种方式之一来执行此操作。

>>> a[-2:2:1]   # the step = 1 is necessary
[0, 0, 1, 2]

>>> a[slice(-2,2)]
[0, 0, 1, 2]

两端都有效:

>>> a[-2:6:1]
[0, 0, 1, 2, 3, 0, 0, 0]

原始尝试

如果__getslice__传递了a[-2:2]给出的实际参数,那么这将有效:

class MyList(list):
    def __getitem__(self, item):
        if item < 0 or item >= len(self):
            return 0
        return super(MyList, self).__getitem__(item)

    def __getslice__(self, s, e):
        print "input: ", s, e
        l = len(self) - 1
        left = -s if s < 0 else 0
        s = max(s, 0)
        right = e - l if e > l else 0
        e = min(e, l)

        return [0]*left + super(MyList, self).__getslice__(s,e) + [0]*right

但由于某些原因,a[-2:2]调用a.__getslice(2,2)并且两个值均为正值。

>>> a[-2:2]
input: 2 2

答案 5 :(得分:0)

列表中的随机索引len仅适用于切片。如果要获取(或设置)某些对象,则必须仅在列表范围内使用索引。 所以

L[4]=0
x=L[4]

不起作用,但

L[4:6]=0,0 or L[4:6]=[0,0]
x,y=L[2:10000] # x=3,y=4

将起作用