如何在Python中安全地从列表中删除元素

时间:2011-02-10 18:12:09

标签: python list iterator

我遍历列表并删除满足我条件的元素。但是,为什么这不起作用,如下所述?谢谢。

>>> a=[ i for i in range(4)]
>>> a
[0, 1, 2, 3]
>>> for e in a:
...     if (e > 1) and (e < 4):
...         a.remove(e)
... 
>>> a
[0, 1, 3]
>>> a=[ i for i in range(4)]
>>> for e in a:
...     if (e > -1) and (e < 3):
...         a.remove(e)
... 
>>> a
[1, 3]

5 个答案:

答案 0 :(得分:10)

在迭代时你无法改变某些东西。结果很奇怪,反直觉,几乎不是你想要的。实际上,许多集合明确地禁止这样做(例如集和词组)。

相反,迭代副本(for e in a[:]: ...)或者,而不是修改现有列表,过滤它以获取包含所需项目的新列表([e for e in a if ...])。请注意,在许多情况下,您不必再次迭代进行过滤,只需将过滤与数据生成合并。

答案 1 :(得分:6)

为什么不在列表理解中最初这样做? E.g。

[i for i in range(4) if i <= 1 or i >= 4]

您也可以使用它从现有列表构建新列表,例如

[x for x in a if x <= 1 or x >= 4]

答案 2 :(得分:3)

过滤的想法很好,但它忽略了一些列表可能非常大并且要删除的元素数量可能非常小。

在这种情况下,答案是记住要删除的元素的列表索引,然后遍历索引列表,从最大到最小排序,删除元素。

答案 3 :(得分:3)

最简单的可视化方法是考虑迭代处理列表偏移而不是实际项目 - 对第一个项目执行操作,然后执行第二个项目,然后执行第三个项目,直到项目用完为止。如果更改列表中的项目数,则会更改列表中所有剩余项目的偏移量:

lst = [1,2,3,4]
for item in lst:
    if item==2:
        lst.remove(item)
    else:
        print item
print lst

结果

1
4
[1,3,4]

如果您像这样单步执行它是有意义的:

[1,2,3,4]
 ^
 first item is not 2, so print it -> 1

[1,2,3,4]
   ^
   second item is 2, so remove it

[1,3,4]
     ^
     third item is 4, so print it -> 4

唯一真正的解决方案是在迭代时不改变列表中的项目数。将要保留的项目复制到新列表,或跟踪要删除的值,并在单独的传递中执行按值删除。

答案 4 :(得分:1)

在迭代过程中从列表中删除元素是不安全的。因为存在过滤功能。它需要一个函数(允许一个参数)和一个iterable(在这种情况下是你的列表)。它返回一个相同类型的新迭代(这里再次列出),其中应用于该元素的函数的元素返回True:

在你的情况下,你可以使用这样的lambda函数:

a = filter(lambda x: x > 1 and x < 4, range(4))

或者如果你已经有了清单:

a = range(4)
a = filter(lambda x: x > 1 and x < 4, a)

请记住,如果您使用的是python3,它将返回迭代器而不是列表。