这是对一个类似 问题 的跟进,该问题询问了最好的写作方式
for item in somelist:
if determine(item):
code_to_remove_item
似乎共识是在类似的事情上
somelist[:] = [x for x in somelist if not determine(x)]
但是,我认为如果您只删除一些项目,那么大部分项目都会被复制到同一个对象中,这可能会很慢。在另一个相关 问题 的 回答 中,有人建议:
for item in reversed(somelist):
if determine(item):
somelist.remove(item)
但是,这里的 list.remove
将搜索列表长度为 O(N) 的项目。可能我们的限制在于列表表示为数组,而不是链表,因此删除项目将需要移动它后面的所有内容。不过 这里 建议用双向链表来表示collections.dequeue。然后应该可以在迭代时在 O(1) 中删除。我们将如何真正做到这一点?
更新:我也做了一些时间测试,代码如下:
import timeit
setup = """
import random
random.seed(1)
b = [(random.random(),random.random()) for i in xrange(1000)]
c = []
def tokeep(x):
return (x[1]>.45) and (x[1]<.5)
"""
listcomp = """
c[:] = [x for x in b if tokeep(x)]
"""
filt = """
c = filter(tokeep, b)
"""
print "list comp = ", timeit.timeit(listcomp,setup, number = 10000)
print "filtering = ", timeit.timeit(filt,setup, number = 10000)
并得到:
list comp = 4.01255393028
filtering = 3.59962391853
原文由 highBandWidth 发布,翻译遵循 CC BY-SA 4.0 许可协议
列表理解是渐近最优解:
它只对列表进行一次传递,因此运行时间为 O(n)。由于您需要在每个对象上调用 determine(),因此任何算法都至少需要 O(n) 次操作。列表推导式确实需要进行一些复制,但它只是复制对对象的引用,而不是复制对象本身。
在 Python 中从列表中删除项目的时间复杂度为 O(n),因此在循环内使用 remove、pop 或 del 的任何内容的时间复杂度为 O(n**2)。
此外,在 CPython 中,列表理解比 for 循环更快。