如何从循环内正确修改python中循环的迭代器

时间:2011-12-17 11:58:21

标签: python loops iterator

我基本上需要检查列表中的每个元素,如果某些条件合适,我想从列表中删除它。

例如,让我们说

list=['a','b','c','d','e']

我基本上想写(原则上而不是我试图实现的实际代码)

如果列表中的元素为“b”或“c”,请将其从列表中删除,然后执行下一步。

但是

for s in list:
    if s=='b' or s=='c':
        list.remove(s)

失败,因为当'b'被移除时,循环取'd'而不是'c'作为下一个元素。那么有没有办法比将元素存储在单独的列表中并在之后删除它们更快?

感谢。

4 个答案:

答案 0 :(得分:10)

更简单的方法是使用列表的副本 - 可以使用从列表的“从开头”延伸到“结尾”的切片来完成,如下所示:

for s in list[:]:
    if s=='b' or s=='c':
        list.remove(s)

你已经考虑过这个了,这很简单,可以在你的代码中,除非这个列表真的很大,并且在代码的关键部分(比如,在动作游戏的主循环中)。在这种情况下,我有时使用以下习语:

to_remove = []
for index, s in enumerate(list):
    if s == "b" or s == "c":
         to_remove.append(index)

for index in reversed(to_remove):
    del list[index]

当然,您可以使用while循环:

index = 0
while index < len(list):
   if s == "b" or s == "c":
       del list[index]
       continue
   index += 1

答案 1 :(得分:8)

最好不要重新发明现有的东西。在这些情况下使用filter函数和lambda。它更加pythonic,看起来更干净。

filter(lambda x:x not in ['b','c'],['a','b','c','d','e'])

或者你可以使用列表理解

[x for x in ['a','b','c','d','e'] if x not in ['b','c']]

答案 2 :(得分:3)

这正是itertools.ifilter的设计目标。

from itertools import ifilter

ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])

会为您的列表返回一个生成器。如果您确实需要一个列表,可以使用一种将生成器转换为列表的标准技术来创建它:

list(ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e']))

[x for x in ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])]

答案 3 :(得分:1)

如果您可以创建列表副本,可以这样做(list comprehension):

[s for s in list if s != 'b' and s != 'c']