python:在遍历列表时删除列表元素

Python: Removing list element while iterating over list

本问题已经有最佳答案,请猛点这里访问。

我正在迭代Python中的元素列表,对其执行一些操作,然后在满足某些条件时删除它们。

1
2
3
4
for element in somelist:
    do_action(element)
    if check(element):
        remove_element_from_list

我应该用什么来代替删除元素?我也看到过类似的问题,但是请注意,要为所有元素执行的Do-Action部分的存在,从而消除了使用过滤器的解决方案。


您总是可以迭代列表的副本,这样您就可以自由地修改原始列表:

1
2
3
for item in list(somelist):
  ...
  somelist.remove(item)


要满足这些条件:就地修改原始列表,没有列表副本,只有一次通过,有效,传统的解决方案是向后迭代:

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

好处:在每次迭代中都不执行len(somelist)。适用于任何版本的python(至少可以追溯到1.5.2)。s/x range/range/用于3.x。

更新:如果你想向前迭代,它是可能的,只是更狡猾和更丑陋:

1
2
3
4
5
6
7
8
9
10
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


清单:

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


您仍然可以使用filter,将元素修改移到外部函数(仅迭代一次)

1
2
3
4
5
6
7
8
9
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)


1
2
3
for element in somelist:
    do_action(element)
somelist[:] = (x for x in somelist if not check(x))

如果你真的需要一次完成而不复制列表

1
2
3
4
5
6
7
8
i=0
while i < len(somelist):
    element = somelist[i]
    do_action(element)
    if check(element):
        del somelist[i]
    else:
        i+=1


另一种方法是:

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

因此,在检查的同时并排删除元素


您可以生成一个返回所有未删除内容的生成器:

1
2
3
4
5
def newlist(somelist):
    for element in somelist:
        do_action(element)
        if not check(element):
            yield element


不完全到位,但有一些想法:

1
2
3
4
5
6
7
8
9
a = ['a', 'b']

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

您可以扩展函数来调用条件中的过滤器。


为什么不重写成

1
2
3
4
5
for element in somelist:
   do_action(element)  

if check(element):
    remove_element_from_list

请参阅此问题以了解如何从列表中删除,尽管看起来您已经看到了迭代时从列表中移除项

另一个选择是如果你真的想保持这个不变

1
2
3
4
5
6
newlist = []
for element in somelist:
   do_action(element)  

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