好吧,我是 Python 的超级新手,关于切片列表的事情让我很困扰。当我从这段代码中切片 [1] 和 [3] 时,为什么会得到 [1, 3, 4]?
z = [1, 2, 3, 4, 5]
del z[1], z[3]
print z
我以为我会得到 [1, 3, 5] 回来,因为它似乎 [2] 和 [4] 正在被删除。
如果-->[1, 2, 3, 4, 5]
是-->[0, 1, 2, 3, 4]
我的逻辑在哪里搞砸了?
第一次删除会更改列表索引,因此下一个不是以前的位置...简化
>>> a = [1, 2, 3]
>>> del a[0] # should delete 1
>>> a
[2, 3]
>>> del a[1] # This use to be the index for 2, but now `3` is at this index
>>> a
[2]
一次删除一个。第一次删除将所有后续元素向左移动一个位置:
In [3]: z = [1, 2, 3, 4, 5]
In [5]: del z[1]
In [6]: z
Out[6]: [1, 3, 4, 5]
In [7]: z[3]
Out[7]: 5
如果您将索引从最大到最小排列,则不会发生这种情况,因为没有删除会更改任何相关索引:
In [18]: z = [1, 2, 3, 4, 5]
In [19]: del z[3], z[1]
In [20]: z
Out[20]: [1, 3, 5]
当您进行删除时,它们一次发生一个,因此每次删除都会导致向右的值移动到左侧的一个索引上。
z = [1, 2, 3, 4, 5]
del z[1] # [1, X, 3, 4, 5] --> [1, 3, 4, 5]
del z[3] # [1, 3, 4, X] --> [1, 3, 4]
您应该做的保留顺序是将删除从最大索引到最小索引,这样就不会转移任何内容,即
del z[3]; del z[1]
更好的是一次删除所有内容以完全避免该问题:
z = [1, 2, 3, 4, 5]
del z[1::2]
# returns [1, 3, 5]
其他人提到了您的代码有什么问题,我可以真正理解您打算做什么的原因
如果您想删除第 2 个和第 4 个元素并且不太关心移位列表,您应该在一个单一的范围内执行此操作,可能的解决方案是通过 List COMprehension
def inplace_del(it, rng):
return [e for i, e in enumerate(it) if i not in set(rng)]
inplace_del(z,(2,3))
[1, 2, 5]
y = xrange(1,6)
inplace_del(y,(2,3))
[1, 2, 5]
更好的解决方案是使用 itertools
>>> from itertools import count, compress
>>> def in_del(it, rng):
rng = set(rng)
holes = (e not in rng for e in count(0))
return compress(it, holes)
>>> list(in_del(z,(2,3)))
[1, 2, 5]
>>> list(in_del(y,(2,3)))
[1, 2, 5]
>>>
您看到这种行为的原因是,这del z[1], z[3]
完全等同于在单独的行上设置del z[1]
和。del z[3]
所以第一个del
语句将移动后续元素并z[3]
成为最后一个元素(5
):
>>> def del_test():
... del z[1], z[3]
...
>>> def del_test2():
... del z[1]
... del z[3]
...
>>> del_test.__code__.co_code == del_test2.__code__.co_code
True