Python:List vs Dict查找表

时间:2009-02-04 23:28:41

标签: python performance

我需要在某种类型的查找表中添加大约1000万个值,所以我想知道哪个列表 dict 更有效?< / p>

我知道你可以为这两件事做这样的事情:

if something in dict_of_stuff:
    pass

if something in list_of_stuff:
    pass

我的想法是dict会更快,更有效率。

感谢您的帮助。

编辑1
关于我正在尝试做什么的更多信息。 Euler Problem 92。我正在查找表,看看计算出的值是否已经准备就绪。

编辑2
查找效率。

编辑3
没有与值相关的值......那么会更好吗?

8 个答案:

答案 0 :(得分:195)

速度

列表中的查找是O(n),字典中的查找是按照数据结构中的项目数量分摊的O(1)。如果您不需要关联值,请使用集。

内存

字典和集合都使用散列,并且它们使用的内存比仅用于对象存储的内存多得多。根据A.M. Kuchling在 Beautiful Code 中,实现试图保持哈希2/3满,所以你可能会浪费相当多的内存。

如果您没有动态添加新条目(根据更新的问题,您可以这样做),可能值得对列表进行排序并使用二进制搜索。这是O(log n),对于字符串来说可能更慢,对于没有自然排序的对象来说是不可能的。

答案 1 :(得分:38)

dict是一个哈希表,所以找到密钥真的很快。所以在dict和list之间,dict会更快。但是如果你没有要关联的值,那么使用一个集合会更好。它是一个哈希表,没有“表”部分。


编辑:对于你的新问题,是的,一套会更好。只需创建2个集合,一个用于以1结尾的序列,另一个用于以89结尾的序列。我已成功使用集合解决了这个问题。

答案 2 :(得分:31)

set()正是您想要的。 O(1)查找,小于dict。

答案 3 :(得分:26)

我做了一些基准测试,事实证明dict比大型数据集的列表和设置更快,在Linux上的i7 CPU上运行python 2.7.3:

  • python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'

    10个循环,最佳3:每循环64.2毫秒

  • python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'

    10000000循环,最佳3:0.0759每循环使用

  • python -mtimeit -s 'from sets import Set; d=Set(range(10**7))' '5*10**6 in d'

    1000000循环,最佳3:每循环0.262 usec

正如您所看到的,dict比列表快得多,速度比set快3倍。但是在某些应用程序中,您可能仍然希望选择适合它的美丽。如果数据集非常小(<1000个元素),则列表表现相当不错。

答案 4 :(得分:6)

如果数据是唯一的set()将是最有效的,但是两个 - dict(也需要唯一性,oops :)。

答案 5 :(得分:6)

你想要一个字典。

对于Python中的(未排序)列表,“in”操作需要O(n)时间 - 当你有大量数据时不好。另一方面,dict是一个哈希表,所以你可以期待O(1)查找时间。

正如其他人所说,如果你只有键而不是键/值对,你可以选择一组(一种特殊类型的dict)。

相关:

  • Python wiki:有关Python容器操作的时间复杂性的信息。
  • SO:Python容器操作时间和内存复杂性

答案 6 :(得分:2)

作为展示@ 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

在这里,我们还比较了tuple,在某些用例中,已知liststuple更快(并且使用更少的内存)。在查找表的情况下,dict没有更好的结果。

setl=[1,2,3,1,2,1,4]都表现得非常好。这引出了一个有趣的观点,即@SilentGhost关于唯一性的答案:如果OP在数据集中有10M的值,并且如果它们中有重复,那么它是未知的,那么值得保留一个set / dict它的元素与实际数据集并行,并测试该集合/字典中是否存在。可能10M数据点只有10个唯一值,这是一个小得多的搜索空间!

SilentGhost关于dicts的错误实际上是有启发性的,因为可以使用dict将重复数据(在值中)关联到非重复集(键)中,从而保持一个数据对象保存所有数据,但仍然是快速查找表。例如,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

有了这个词,人们可以知道:

  1. 如果原始数据集中有值(即True返回d[2]
  2. 其中值在原始数据集中(即[1, 4]返回在原始数据列表中找到数据的索引列表:{{1}})

答案 7 :(得分:0)

你实际上并不需要在表格中存储1000万个值,所以这不是什么大问题。

提示:考虑在第一个平方和操作后你的结果有多大。最大可能的结果将远远小于1000万......