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

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

我应该用什么来代替code_to_remove_tup?我不知道怎么用这种方式把东西拿掉。


当前回答

如果希望在迭代时从列表中删除元素,请使用while循环,以便在每次删除后都可以更改当前索引和结束索引。

例子:

i = 0
length = len(list1)

while i < length:
    if condition:
        list1.remove(list1[i])
        i -= 1
        length -= 1

    i += 1

其他回答

您需要获取列表的副本并首先对其进行迭代,否则迭代将失败,可能会出现意想不到的结果。

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

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
[]

对于这样的示例,最好的方法是列表理解

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

如果您要做的事情比调用确定函数更复杂,我更喜欢构造一个新列表,并在执行过程中简单地追加它。例如

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

使用remove复制列表可能会使您的代码看起来更简洁,如下面的其中一个答案所述。对于非常大的列表,您绝对不应该这样做,因为这涉及到首先复制整个列表,并对被删除的每个元素执行O(n)删除操作,使其成为O(n^2)算法。

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)

最有效的方法是列表理解,很多人展示了他们的案例,当然,通过过滤器获得迭代器也是一个很好的方法。

过滤器接收一个函数和一个序列。Filter依次将传递的函数应用于每个元素,然后根据函数的返回值是True还是False来决定是否保留或丢弃该元素。

这里有一个例子(获取元组中的概率):

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

警告:你也可以不处理迭代器。迭代器有时比序列更好。

您可以使用列表推导式创建一个新列表,其中只包含您不想删除的元素:

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

或者,通过分配slice somlist[:],你可以改变现有的列表,只包含你想要的项:

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

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

你也可以使用itertools来代替理解函数。在Python 2中:

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

或者在python3中:

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

for循环将遍历一个索引…

假设你有一个清单,

[5, 7, 13, 29, 65, 91]

您使用了一个名为lis的列表变量。你用同样的方法来移除…

你的变量

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

在第5次迭代中,

你的数字35不是质数,所以你把它从列表中删除了。

lis.remove(y)

然后下一个值(65)移动到前一个索引。

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

所以第四次迭代完成指针移动到第五次…

这就是为什么你的循环没有覆盖65,因为它已经移动到前一个索引。

因此,你不应该将一个列表引用到另一个变量中,它仍然引用原始变量而不是副本。

ite = lis # Don’t do it will reference instead copy

所以使用list[::]复制列表。

现在你会付出,

[5, 7, 13, 29]

问题是你在迭代过程中从列表中删除了一个值,然后你的列表索引就会崩溃。

所以你可以试试列表理解。

它支持所有的可迭代对象,如list, tuple, dict, string等。