作为一组新的测试,以表明@EriF89在这么多年后仍然是正确的:
$ python -m timeit -s "l={k:k for k in xrange(5000)}" "[i for i in xrange(10000) if i in l]"
1000 loops, best of 3: 1.84 msec per loop
$ python -m timeit -s "l=[k for k in xrange(5000)]" "[i for i in xrange(10000) if i in l]"
10 loops, best of 3: 573 msec per loop
$ python -m timeit -s "l=tuple([k for k in xrange(5000)])" "[i for i in xrange(10000) if i in l]"
10 loops, best of 3: 587 msec per loop
$ python -m timeit -s "l=set([k for k in xrange(5000)])" "[i for i in xrange(10000) if i in l]"
1000 loops, best of 3: 1.88 msec per loop
这里我们还比较了一个元组,在某些用例中,元组比列表更快(并且使用更少的内存)。在查找表的情况下,元组也没有更好。
字典和电视机都表现得很好。这就涉及到@SilentGhost关于唯一性的回答:如果OP在一个数据集中有10M个值,并且其中是否存在重复值是未知的,那么值得将其元素与实际数据集并行保存,并测试其在该集合/字典中的存在性。10M数据点可能只有10个唯一值,这是一个小得多的搜索空间!
SilentGhost关于字典的错误实际上很有启发性,因为人们可以使用字典将复制的数据(在值中)关联到一个非复制的集(键)中,从而保持一个数据对象来保存所有数据,但仍然像查找表一样快。例如,dict键可以是正在查找的值,而值可以是该值所在的虚构列表中的索引列表。
例如,如果要搜索的源数据列表是l=[1,2,3,1,2,1,4],可以通过将其替换为以下dict来优化搜索和内存:
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> l=[1,2,3,1,2,1,4]
>>> for i, e in enumerate(l):
... d[e].append(i)
>>> d
defaultdict(<class 'list'>, {1: [0, 3, 5], 2: [1, 4], 3: [2], 4: [6]})
有了这个词典,我们可以知道:
如果一个值在原始数据集中(即2 in d返回True)
值在原始数据集中的位置(即[2]返回在原始数据列表中找到数据的索引列表:[1,4])