最近有人问我关于在迭代时更改列表的失礼之处。他们给出了以下场景(我现在用更好的例子更新了它)作为可能的用例,当行为可能是合乎需要的时候:
>>> jersey_numbers = [4, 2, 3, 5, 1] # list of places in a race
>>> for jersey_number in jersey_numbers:
if jersey_number == 2: # disqualify jersey number 2 for a false start
t.remove(jersey_number)
>>> t
[4, 3, 5, 1] # jersey number 3 is now in second place
这种行为是否足够规则,可以在这样的用例中使用?
发布于 2013-01-25 18:23:43
当您从列表中删除一个项目时,列表中的所有内容都会移动...
[1, 2, 3, 4, 5]
#remove ^
[1, 2, 3, 5]
如果您在迭代对象时执行此操作,并且您希望移除彼此相邻的项,则当您移除第一个项时,第二个项将移位以取代它的位置。for循环将继续递增列表中它从列表中拉取值的位置,这会导致它跳过跳过的值,以取代您删除的项。
这是一个reference --让我们都知道这是一个有充分记录的行为:)
发布于 2013-01-25 18:32:22
你应该使用的是:
t = filter(None, t) # or
t = [x for x in t if x]
或者如果你的情况实际上更复杂:
t = filter(lambda x: x != something, t) # or
t = [x for x in t if x != something]
顺便说一句,remove
删除了第一个匹配的元素,不一定是你的x
当前指向的元素,尽管在你的例子中,简单的行为是等效的。
发生的情况是,当您迭代列表时,您删除了元素,而迭代器不知道这一点,假设您的列表是[1,0,0,2]
1
,没有变化,下一个0
,你删除了一些第一个代码,列表改变了大小,现在迭代器指向第二个零,next2
,没有变化< 0
>F2162>
实际上,您的第一个算法每隔一秒就删除一次零。
你的第二个算法不应该工作,如果你说它工作,也许你没有对它进行足够的测试。
发布于 2013-01-25 18:20:34
错误在于你在遍历列表的时候修改了它。这并不是您所期望的行为(当您删除当前元素时,下一个元素将被跳过)。
下面是如何做到这一点:
In [18]: t = [5.0, 5.0, 5.0, 4.0, 0.0, 5.0, 0.0, 3.0, 5.0, 5.0, 0.0, 0.0, 4.0, 5.0, 0.0, 5.0, 4.0, 5.0, 3.0, 3.0, 5.0, 5.0, 5.0, 5.0]
In [19]: t[:] = [val for val in t if val != 0]
https://stackoverflow.com/questions/14527966
复制