简体   繁体   English

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

[英]how to correctly modify the iterator of a loop in python from within the loop

what I basically need is to check every element of a list and if some criteria fit I want to remove it from the list. 我基本上需要检查列表的每个元素,如果某些条件适合我想从列表中删除它。

So for example let's say that 例如,让我们这样说吧

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

I basically want to write (in principle and not the actual code I try to implement) 我基本上想写(原则上而不是我尝试实现的实际代码)

If an element of the list is 'b' or 'c' remove it from the list and take the next. 如果列表中的元素为“b”或“c”,请将其从列表中删除,然后执行下一个操作。

But

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

fails because when 'b' is removed the loop takes 'd' and not 'c' as the next element. 失败是因为当'b'被移除时,循环取'd'而不是'c'作为下一个元素。 So is there a way to do that faster than storing the elements in a separate list and removing them afterwards? 那么有没有办法比将元素存储在单独的列表中并在之后删除它们更快?

Thanks. 谢谢。

The easier way is to use a copy of the list - it can be done with a slice that extends "from the beginning" to the "end" of the list, like this: 更简单的方法是使用列表的副本 - 可以使用从列表的“从头开始”延伸到“结束”的切片来完成,如下所示:

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

You have considered this, and this is simple enough to be in your code, unless this list is really big, and in a critical part of the code (like, in the main loop of an action game). 您已经考虑过这一点,这很简单,可以在您的代码中,除非此列表非常大,并且在代码的关键部分(例如,在动作游戏的主循环中)。 In that case, I sometimes use the following idiom: 在这种情况下,我有时会使用以下习语:

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]

Of course you can resort to a while loop instead: 当然你可以使用while循环:

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

Its better not to reinvent things which are already available. 最好不要重新发明现有的东西。 Use filter functions and lambda in these cases. 在这些情况下使用过滤器函数和lambda。 Its more pythonic and looks cleaner. 它更加pythonic,看起来更干净。

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

alternatively you can use list comprehension 或者你可以使用列表理解

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

This is exactly what itertools.ifilter is designed for. 这正是itertools.ifilter的设计目标。

from itertools import ifilter

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

will give you back a generator for your list. 将为您的列表返回一个生成器。 If you actually need a list, you can create it using one of the standard techniques for converting a generator to a list: 如果您确实需要一个列表,可以使用一种将生成器转换为列表的标准技术来创建它:

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

or 要么

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

如果你可以创建列表的副本,你可以这样做( 列表理解 ):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM