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

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

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


当前回答

我需要用一个巨大的列表来做这件事,复制列表似乎很昂贵,特别是因为在我的情况下,删除的数量与保留的项目相比很少。我采用了这种低层次的方法。

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

我不知道的是,与复制一个大列表相比,几个删除操作的效率有多高。如果你有什么见解,请评论。

其他回答

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

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

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

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

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

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

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

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

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

对于喜欢函数式编程的人:

somelist[:] = filter(lambda tup: not determine(tup), somelist)

or

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

对于任何有潜力做大的东西,我使用以下方法。

import numpy as np

orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])

remove_me = [100, 1]

cleaned = np.delete(orig_list, remove_me)
print(cleaned)

这应该比其他任何东西都快得多。

for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

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

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