如何在迭代时从列表中删除项目?

2024-04-25 15:13:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Python中迭代一个元组列表,并试图在它们满足某些条件时删除它们。

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

我应该用什么来代替code_to_remove_tup?我想不出怎么用这种方式把这个东西拿走。


Tags: toin列表forif方式code条件
3条回答

您需要获取列表的副本并首先对其进行迭代,否则迭代将失败,并可能产生意外的结果。

例如(取决于列表的类型):

for tup in somelist[:]:
    etc....

例如:

>>> somelist = range(10)
>>> for x in somelist:
...     somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]

>>> somelist = range(10)
>>> for x in somelist[:]:
...     somelist.remove(x)
>>> somelist
[]

提示列表理解的答案几乎是正确的——除了它们构建了一个全新的列表,然后将其命名为与旧列表相同的名称之外,它们不会就地修改旧列表。这与通过选择性删除(如@Lennart's suggestion)所做的不同——它更快,但如果通过多个引用访问列表,则只重新放置其中一个引用而不更改列表对象本身可能会导致微妙的、灾难性的错误。

幸运的是,很容易获得列表理解的速度和所需的就地更改语义——只需编写代码:

somelist[:] = [tup for tup in somelist if determine(tup)]

注意与其他答案的细微区别:这个答案不是指定给barename,而是指定给恰好是整个列表的列表片段,从而替换同一Python列表对象中的列表内容,而不是像其他答案一样重新放置一个引用(从以前的列表对象到新的列表对象)。

您可以使用列表理解创建一个新列表,其中仅包含不想删除的元素:

somelist = [x for x in somelist if not determine(x)]

或者,通过分配给切片somelist[:],可以对现有列表进行变异,使其仅包含所需的项:

somelist[:] = [x for x in somelist if not determine(x)]

如果有其他对somelist的引用需要反映更改,则此方法可能很有用。

您也可以使用itertools,而不是理解。在Python 2中:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

或者在Python 3中:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

相关问题 更多 >