为什么循环不起作用?我的目标是从列表中删除每个1
。
>>> s=[1,4,1,4,1,4,1,1,0,1]
>>> for i in s:
... if i ==1: s.remove(i)
...
>>> s
[4, 4, 4, 0, 1]
答案 0 :(得分:6)
迭代时不要更改列表。结果是不可预测的,正如您在这里看到的那样。一个简单的替代方案是构建一个新列表:
s = [i for i in s if i != 1]
如果由于某种原因你绝对需要编辑列表而不是构建一个新列表,我的袖手旁观的最佳答案是遍历它找到必须删除的索引,然后反向遍历索引列表逐个删除它们:
indices_to_remove = [i for (i, val) in enumerate(s) if val == 1]
for i in reversed(indices_to_remove):
del s[i]
因为它首先从列表末尾删除元素,所以计算出的原始索引仍然有效。但除非特殊情况适用,否则我通常更喜欢计算新列表。
答案 1 :(得分:5)
考虑以下代码:
#!/usr/bin/env python
s=[1, 4, 1, 4, 1, 4, 1, 1, 0, 1]
list_size=len(s)
i=0
while i!=list_size:
if s[i]==1:
del s[i]
list_size=len(s)
else:
i=i + 1
print s
结果:
[4, 4, 4, 0]
简而言之,您的代码会产生一些不良结果,因为每次关闭1
数字时,列表的“大小”和“索引位置”都会更改,并且您的代码已明确证明{{1} for each loop
中的{}无法处理动态大小的列表。
答案 2 :(得分:3)
这不起作用,因为您在迭代时修改列表,并且当前指针移过您检查的1
之一。我们可以说明这一点:
>>> for i in s:
... print(s)
... if i == 1:
... s.remove(i)
...
[1_, 4, 1, 4, 1, 4, 1, 1, 0, 1]
[4, 1_, 4, 1, 4, 1, 1, 0, 1]
[4, 4, 1_, 4, 1, 1, 0, 1]
[4, 4, 4, 1_, 1, 0, 1]
[4, 4, 4, 1, 0_, 1]
[4, 4, 4, 1, 0, 1_]
我将_
添加到要比较的元素中。请注意,总共只有6次传递,并且其中一个1
实际上已被跳过了。这最终成为被移除的元素,因为list.remove
删除了指定元素的第一次出现,并且它本身就是一个O(n)操作,一旦你的列表获得非常昂贵变大 - 这是O(n)即使项目在开头,因为它必须从项目一元素前面的所有内容复制每一个项目,因为python list
更像是C样式的数组而不是Java链接列表(如果要使用链接列表,请使用collections.deque
)。 O(n)即将结束,因为它必须遍历整个列表以进行自己的比较。如果您使用remove
,生成的代码可能会导致运行时最严重的O(n log n)。
请参阅Python's data structure time complexity
彼得的回答已经涵盖了新列表的生成,我只回答了原始代码无法正常工作的原因和方式。
答案 3 :(得分:3)
迭代时不应更改列表的内容
但是你可以迭代列表内容的副本并在你的情况下改变它
<强>代码:强>
s=[1,4,1,4,1,4,1,1,0,1]
for i in s[:]:
if i ==1: s.remove(i)
print s
<强>输出:强>
[4, 4, 4, 0]
正如@metatoaster所说,你可以使用filter
<强>代码:强>
s=[1,4,1,4,1,4,1,1,0,1]
s=list(filter(lambda x:x !=1,s))
print s
[4, 4, 4, 0]
您可以使用过滤器删除多个示例
<强>代码:强>
s=[1,4,1,4,1,4,1,1,0,1,2,3,5,6,7,8,9,10,20]
remove_element=[1,2,3,5,6,7,8,9]
s=list(filter(lambda x:x not in remove_element,s))
print s
[4, 4, 4, 0, 10, 20]