Python: 在遍历 list 时删除 list 元素

我在 Python 中迭代一个元素列表,对它执行一些操作,然后如果它们满足某些条件,就删除它们。

for element in somelist:
do_action(element)
if check(element):
remove_element_from_list

我应该用什么来代替 move _ element? 我曾经看到过类似的问题,但是请注意 do _ action 部分的存在,它将对所有元素执行,从而消除了使用过滤器的解决方案。

165881 次浏览

You could always iterate over a copy of the list, leaving you free to modify the original:

for item in list(somelist):
...
somelist.remove(item)
for element in somelist:
do_action(element)
somelist[:] = (x for x in somelist if not check(x))

If you really need to do it in one pass without copying the list

i=0
while i < len(somelist):
element = somelist[i]
do_action(element)
if check(element):
del somelist[i]
else:
i+=1

Why not rewrite it to be

for element in somelist:
do_action(element)


if check(element):
remove_element_from_list

See this question for how to remove from the list, though it looks like you've already seen that Remove items from a list while iterating

Another option is to do this if you really want to keep this the same

newlist = []
for element in somelist:
do_action(element)


if not check(element):
newlst.append(element)

You can still use filter, moving to an outside function the element modification (iterating just once)

def do_the_magic(x):
do_action(x)
return check(x)


# you can get a different filtered list
filter(do_the_magic,yourList)


# or have it modified in place (as suggested by Steven Rumbalski, see comment)
yourList[:] = itertools.ifilter(do_the_magic, yourList)

List comp:

results = [x for x in (do_action(element) for element in somelist) if check(element)]

You can make a generator that returns everything that isn't removed:

def newlist(somelist):
for element in somelist:
do_action(element)
if not check(element):
yield element

To meet these criteria: modify original list in situ, no list copies, only one pass, works, a traditional solution is to iterate backwards:

for i in xrange(len(somelist) - 1, -1, -1):
element = somelist[i]
do_action(element)
if check(element):
del somelist[i]

Bonus: Doesn't do len(somelist) on each iteration. Works on any version of Python (at least as far back as 1.5.2) ... s/xrange/range/ for 3.X.

Update: If you want to iterate forwards, it's possible, just trickier and uglier:

i = 0
n = len(somelist)
while i < n:
element = somelist[i]
do_action(element)
if check(element):
del somelist[i]
n = n - 1
else:
i = i + 1

Another way of doing so is:

while i<len(your_list):
if #condition :
del your_list[i]
else:
i+=1

So, you delete the elements side by side while checking

Not exactly in-place, but some idea to do it:

a = ['a', 'b']


def inplace(a):
c = []
while len(a) > 0:
e = a.pop(0)
if e == 'b':
c.append(e)
a.extend(c)

You can extend the function to call you filter in the condition.