【问题标题】:Remove the object being iterated over from list从列表中删除正在迭代的对象
【发布时间】:2013-06-13 16:18:41
【问题描述】:

考虑:

fooList = [1, 2, 3, 4] # Ints for example only, in real application using objects

for foo in fooList:
    if fooChecker(foo):
        remove_this_foo_from_list

如何从列表中删除特定的foo?请注意,我仅使用整数作为示例,在实际应用程序中存在任意对象的列表。

谢谢。

【问题讨论】:

  • 值得注意的是another answer 的内容,这表明构建新列表比就地修改列表更有效。如果您需要就地执行,my_list.remove(my_item) 特别糟糕,因为它是 O(n) 查找 - 请改用 del my_list[index]
  • @Aya 但是你必须按索引迭代(或使用enumerate() - 仍然很难看) - 因此我建议只构建一个新列表,然后在需要修改现有列表时重新分配。当然,一般来说,人们可以只建立一个新列表而忘记旧列表。
  • @Lattyware 确实如此。另请参阅我对您的回答的评论。

标签: python list


【解决方案1】:

通常,您只是不想这样做。相反,请构建一个新列表。大多数情况下,这是通过list comprehension 完成的:

fooListFiltered = [foo for foo in fooList if not fooChecker(foo)]

或者,生成器表达式(我上面链接的视频涵盖生成器表达式以及列表推导)或 filter()(请注意,在 2.x 中,filter()not 惰性的 - 使用生成器表达式或 itertools.ifilter() 代替)可能更合适(例如,太大而无法读入内存的大文件不会以这种方式工作,但可以使用生成器表达式)。

如果您需要实际修改列表(很少见,但有时会出现这种情况),那么您可以分配回去:

fooList[:] = fooListFiltered

【讨论】:

  • 由于 OP 的 fooChecker() 返回 True 以从列表中删除项目,您还可以提及 itertools.ifilterfalse(fooChecker, fooList)
【解决方案2】:

遍历列表的浅表副本。

由于您无法在迭代时修改列表,因此您需要迭代列表的浅表副本。

fooList = [1, 2, 3, 4] 

for foo in fooList[:]: #equivalent to list(fooList), but much faster
    if fooChecker(foo):
        fooList.remove(foo)

【讨论】:

  • +1,这是另一种方法。只是为了解释一下,需要副本以确保在您迭代列表时不会更改列表,因为这会导致不需要的行为。
【解决方案3】:

使用filter:

newList = list(filter(fooChecker, fooList))

newItems = filter(fooChecker, fooList))

for item in newItems:
    print item # or print(item) for python 3.x

http://docs.python.org/2/library/functions.html#filter

【讨论】:

  • -1 - 这将生成应删除的所有值的列表 - 与请求的内容完全相反
  • 那么告诉我,否定一个条件有多难?鉴于filter 可以生成真正可读的代码?
  • 确实我承认我的错误,但我认为这不是根本性的,OP可以自己解决。
  • 然后更改您的答案以包含该注释 - 鉴于它反转执行的操作,这非常重要。
猜你喜欢
  • 1970-01-01
  • 2019-02-12
  • 2017-02-10
  • 2012-04-01
  • 1970-01-01
  • 2016-12-02
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
相关资源
最近更新 更多