簡體   English   中英

Python:List vs Dict查找表

[英]Python: List vs Dict for look up table

or ? 我有大約1000萬個值,我需要放在某種類型的查找表中,所以我想知道哪個更有效?

我知道你可以做兩件事:

if something in dict_of_stuff:
    pass

if something in list_of_stuff:
    pass

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

謝謝你的幫助。

編輯1
關於我正在嘗試做什么的更多信息。 歐拉問題92 我正在查找表,看看計算出的值是否已經准備就緒。

編輯2
查找效率。

編輯3
be better? 沒有與值相關的值......那么一會更好嗎?

速度

列表中的查找是O(n),字典中的查找是分攤的O(1),關於數據結構中的項目數。 如果您不需要關聯值,請使用集合。

記憶

字典和集合都使用散列,並且它們使用的內存比僅用於對象存儲的內存多得多。 根據AM Kuchling的漂亮代碼 ,實現試圖保持哈希2/3滿,所以你可能會浪費相當多的內存。

如果您不動態添加新條目(根據更新的問題,您可以這樣做),可能需要對列表進行排序並使用二進制搜索。 這是O(log n),對於字符串來說可能更慢,對於沒有自然排序的對象來說是不可能的。

dict是一個哈希表,所以找到密鑰真的很快。 所以在dict和list之間,dict會更快。 但是如果你沒有要關聯的值,那么使用一個集合會更好。 它是一個哈希表,沒有“表”部分。


編輯:對於你的新問題,是的,一套會更好。 只創建2組,一組用於序列以1結尾,另一組用於以89結尾的序列。我已成功使用集合解決了這個問題。

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

我做了一些基准測試,事實證明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'

    10000循環,最佳3:0.0759 usec每循環

  • 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個元素),那么列表表現相當不錯。

如果數據是唯一的set()將是最有效的,但是兩個 - dict(也需要唯一性,oops :)

你想要一個字典。

對於Python中的(未排序)列表,“in”操作需要O(n)時間 - 當您有大量數據時不好。 另一方面,dict是一個哈希表,所以你可以期待O(1)查找時間。

正如其他人所指出的那樣,如果你只有鍵而不是鍵/值對,你可以選擇一組(一種特殊類型的dict)。

有關:

  • Python wiki :有關Python容器操作的時間復雜性的信息。
  • SO :Python容器操作時間和內存復雜性

作為展示@ 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 ,在某些用例中,它們比lists更快(並且使用更少的內存)。 在查找表的情況下, tuple沒有更好的結果。

dictset表現得非常好。 這引出了一個有趣的觀點,即@SilentGhost關於唯一性的答案:如果OP在數據集中有10M值,並且不知道它們中是否有重復,則值得保持其元素的set / dict並行使用實際數據集,並測試該set / dict中是否存在。 10M數據點可能只有10個唯一值,這是一個小得多的搜索空間!

SilentGhost關於dicts的錯誤實際上是有啟發性的,因為可以使用dict將重復數據(在值中)關聯到非重復集(鍵)中,從而使一個數據對象保持所有數據,但仍然作為查找表快速。 例如,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]})

通過這個詞,人們可以知道:

  1. 如果值在原始數據集中(即2 in d返回True
  2. 其中值是在原始數據集(即d[2]返回在其中數據是在原始數據列表中找到索引列表: [1, 4]

實際上你並不需要在表中存儲1000萬個值,因此無論如何都不是什么大問題。

提示:考慮在第一個平方和操作后你的結果有多大。 最大可能的結果將遠遠小於1000萬...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM