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

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

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


当前回答

一个可能的解决方案,如果你不仅想删除一些东西,而且还想对单个循环中的所有元素做一些事情,这个解决方案很有用:

alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
    if x == 'bad':
        alist.pop(i)
        i -= 1
    # do something cool with x or just print x
    print(x)
    i += 1

其他回答

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

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)
for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

你需要向后走,否则就有点像锯掉你坐着的树枝:-)

Python 2用户:用xrange替换range以避免创建硬编码的列表

建议列表推导的答案几乎是正确的,除了它们构建了一个全新的列表,然后给它一个与旧列表相同的名称,它们没有在适当的地方修改旧列表。这与Lennart建议的选择性删除不同——它更快,但如果您的列表是通过多个引用访问的,那么您只是重新设置了其中一个引用,而没有更改列表对象本身,这可能会导致微妙的、灾难性的错误。

幸运的是,它非常容易获得列表推导式的速度和所需的就地更改的语义——只是代码:

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

请注意与其他答案的细微区别:这个答案没有分配给一个裸名。它赋值给一个列表切片,恰好是整个列表,因此替换了同一Python列表对象中的列表内容,而不是像其他答案一样只是重新设置一个引用(从以前的列表对象到新的列表对象)。

这里的大多数答案都要求您创建列表的副本。我有一个用例,其中列表相当长(110K项),明智的做法是继续减少列表。

首先,你需要用while循环替换foreach循环,

i = 0
while i < len(somelist):
    if determine(somelist[i]):
         del somelist[i]
    else:
        i += 1

i的值在if块中没有改变,因为一旦旧项被删除,您将希望从SAME INDEX中获得新项的值。

如果当前列表项满足所需的条件,那么创建一个新列表可能是聪明的做法。

so:

for item in originalList:
   if (item != badValue):
        newList.append(item)

为了避免用新的列表名称重新编码整个项目:

originalList[:] = newList

注意,来自Python文档:

copy.copy (x) 返回x的浅拷贝。 copy.deepcopy (x) 返回x的深拷贝。