Python:迭代列表时删除列表元素

Scr*_*tch 78 python list

我正在迭代Python中的元素列表,对其执行某些操作,然后在满足特定条件时将其删除.

for element in somelist:
    do_action(element)
    if check(element):
        remove_element_from_list
Run Code Online (Sandbox Code Playgroud)

我应该用什么代替remove_element?我已经看到了类似的问题,但注意到要为所有元素执行的do_action部分的存在,从而消除了使用过滤器的解决方案.

blu*_*ume 139

您可以随时遍历列表的副本,让您可以自由修改原始文件:

for item in list(somelist):
  ...
  somelist.remove(item)
Run Code Online (Sandbox Code Playgroud)

  • 好的,但似乎根本没有表现良好.这不是O(n ^ 2)吗?(这不包括初始列表副本).即时删除元素将是O(n). (5认同)
  • 这看起来很糟糕,`list.remove`通过相等来删除第一次出现的值,如果你试图通过`.remove(0.0)从`[0,1,1.0,0]中删除所有浮点值`等等你最终得到`[1.0,0.0]`这绝对不是**所有浮动被移除的结果. (5认同)
  • 使用地图(或列表推导)的副作用和扔掉结果不是很pythonic (4认同)
  • 替代实施是错误的.您需要在map函数之前反转'toremove'.否则后面的索引指向错误的对象. (3认同)
  • @Scrontch鉴于您"在适当的位置修改列表"的其他标准,这看起来是最干净的解决方案.正如一些人所提到的,你不想迭代你正在修改的同一个列表. (2认同)

Joh*_*hin 122

要满足这些标准:原位修改原始列表,没有列表副本,只有一个通过,有效,传统的解决方案是向后迭代:

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

额外奖励:len(somelist)每次迭代都不做.适用于任何版本的Python(至少可以追溯到1.5.2)... s/xrange/range/for 3.X.

更新:如果你想要向前迭代,那么它是可能的,只是更棘手和更丑陋:

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
Run Code Online (Sandbox Code Playgroud)

  • 你也可以使用`revers(range(len(somelist))``来使它看起来更好一些 (18认同)
  • 它是二次算法 (`O(n**2)`)。这是一个[线性解决方案,如果有很多元素要删除](http://stackoverflow.com/a/2794519/4279) 并且你不想使用[列表理解](http://stackoverflow.com/a /1207461/4279)出于任何原因。 (3认同)

zee*_*kay 10

清单组合:

results = [x for x in (do_action(element) for element in somelist) if check(element)]
Run Code Online (Sandbox Code Playgroud)


Joh*_*ooy 8

for element in somelist:
    do_action(element)
somelist[:] = (x for x in somelist if not check(x))
Run Code Online (Sandbox Code Playgroud)

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

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

  • 你也可以使用一个生成器表达式,然后不构建临时列表:`somelist [:] =(如果没有检查(元素),某些列表中的x为x) (2认同)

Ric*_*lli 7

您仍然可以使用过滤器,移动到外部函数元素修改(迭代一次)

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)
Run Code Online (Sandbox Code Playgroud)

  • 您对`filter`的参数顺序错误.此外,他希望列表修改到位,所以使用`itertools.ifilter`并分配给切片:`yourList [:] = itertools.ifilter(do_the_magic,yourList)` (2认同)