【问题标题】:Zero outside the range of a list / array列表/数组范围之外的零
【发布时间】:2013-12-11 15:23:27
【问题描述】:

使用 Python 列表

L=[1,2,3,4]

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

...
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]

【问题讨论】:

  • 您的意思是在列表边界之外分配(哪些负索引不一定会这样做 - 它们从末尾开始并向后工作)应该创建新条目?现有列表和新条目之间应该发生什么?为什么不直接使用带有整数键的字典?
  • 那么,让我直说吧。您有列表 a 和列表 b。您要做的是将列表b中的所有元素更改为0,而不是列表a的成员?
  • @jonrsharpe 嘿乔恩!好久不见。还记得 Edx 的我吗?如果您有时间,请来 Python 聊天室。
  • 我尝试用__getslice__ 实现切片,但a[-2:2] 语法将(2,2) 传递给__getslice__,因为它不支持否定参数,我不知道如何覆盖它。
  • 我在__getslice__ 上查找了文档,发现它已被弃用。相反,__getitem__ 应该接受切片对象。一个 slice 对象似乎有 start、stop 和 step 三个属性。

标签: python arrays list numpy scipy


【解决方案1】:

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

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

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

【讨论】:

  • 如果我使用负索引,这将不起作用,但也许我应该添加一个 if p &gt; 0
  • 并非总是如此。这个列表空间有限?你知道元素的数量吗?
  • 如果pget(l, p)=0,因此我可能需要添加if
  • 是的。这个就够了
【解决方案2】:

列表 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

会起作用

【讨论】:

    【解决方案3】:

    您可以将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]
    

    【讨论】:

    • hum...dict 似乎是我想要的正确数据类型...它适合大数据量(数千个项目)?
    • 为什么不呢,作为内置数据类型的 dict 非常快。
    【解决方案4】:

    你可以使用一个特殊的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
    

    【讨论】:

    • 有了你的新类 MyList,你知道我们如何修改才能处理像 l2[-2:2]=[0,0,3,5,6] 这样的范围吗?
    • @Basj Python2 还是 Python3 ?我可能有一个解决方案,但它似乎只适用于 Python3。
    • 另外,[3, 5, 6] 代替 [0,0,3,5,6] 会是一个好的解决方案吗?
    • 我使用 Python2。使用您的解决方案,l2[-2:2] 将提供[]。我想要l2[-2:2]=[0,0,3,5,6](不是[3,5,6])。你有这个想法吗?
    • 我仍然找不到如何处理这样的范围......你有什么想法吗?
    【解决方案5】:

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

    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

    【讨论】:

    • 有了这个 MyList 类,你知道如何处理范围,例如 L[0:6]=[1,2,3,4,0,0] 吗?
    • 我已经更新了答案。它仍然有点小错误,但我希望你明白了。
    • 非常感谢!它适用于L[0:6]=[1,2,3,4,0,0] 之类的东西,但仍然不适用于应该给[0,0,1,2,3,4,0,0]L[-2:6]...我对带有切片的 Python 类定义相当陌生,但我希望我可以让它工作:)
    【解决方案6】:

    您可以使用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
    

    【讨论】:

    • 有趣,我们已经接近结果了!
    • 我想我正在取得进步,实际上,使用切片对象。 brb :)
    • 好的,现在可以了。这些列表的可变性可能无法正常运行(例如,b = a[-2:2:1]; b[0] = 88 可能无法执行您希望它执行的操作。但这是一个更棘手的问题。另请注意,我在 python 2 中对此进行了测试。
    • 太棒了!所以它不适用于a[-2:2],我们真的需要a[-2:2:1]
    • @neil 在这种情况下,在 python 3 中会更容易做,但是@Basj is using python 2,所以必须这样做。
    猜你喜欢
    • 1970-01-01
    • 2016-10-05
    • 2013-05-02
    • 2012-06-03
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多