我遍历列表并删除满足我条件的元素。但是,为什么这不起作用,如下所述?谢谢。
>>> 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]
答案 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,它将返回迭代器而不是列表。