簡體   English   中英

效率:python 中的 2D 列表到字典

[英]Efficiency: 2D-list to dictionary in python

我有一個二維列表。

l = [[100, 1], [43, 2], [201, 1], [5, 7], ...]

我想將列表轉換為字典,其中第二個元素作為鍵。 每個鍵的值應該是所有第一個元素的列表,這些元素將鍵作為第二個元素。 此示例列表的字典應如下所示:

{
    1: [100, 201],
    2: [43],
    7: [5],
    ...
}

對於這種轉換,我有兩種解決方案。 其中哪一個更有效,為什么? 另外:還有其他更有效的解決方案嗎?

解決方案1:

d = {}
for elem in l:
    if elem[1] in d:
        d[elem[1]].append(elem[0])
    else:
        d[elem[1]] = [elem[0]]

解決方案2:

d = {}

for elem in l:
    d[elem[1]] = []

for elem in l:
    d[elem[1]].append(elem[0])

你有兩個解決方案沒有錯,它們很好而且高效:

  1. 解決方案 1 迭代列表一次,但執行兩次字典查找。 由於這是關於 O(1),而你有 2,我會說這是 2xN。
  2. 解決方案 2 迭代列表兩次,每次查找一次 - 再次 2xN。

從理論的角度來看,它們是相同的。 運行時間我敢打賭它們也非常接近。 可以改進第一個解決方案的更pythonic方式(請求寬恕而不是許可,感謝@tobias_k)是:

d = {}
for elem in l:
    try:
        d[elem[1]].append(elem[0])
    except KeyError:
        d[elem[1]] = [elem[0]]

如果您有許多重復的鍵,這會更好,因為異常的開銷將比所有 if(並且只有一次查找)小得多,因此這將取決於所討論的實際列表。 如果您選擇此解決方案,您可能需要閱讀defaultdict

一些新信息

我的猜測錯了! 盡管理論上它們是相同的,並且看起來操作量相同,但還是有區別的。 我猜這與 Python 優化if語句的能力有關。

使用timeit模塊標記您的第一個方法a ,第二個b和我提供的c ,我為兩個列表對這些方法計時:

l1=[(x,y) for x,y in zip(range(1000),range(1000,2000)]
l1=[(x,2) for x,y in range(1000)]

l1結果:

方法a最快。 慢 30% 的是b ,另外 30% 是c

l2結果:

方法ab幾乎相同(a 仍然快一點),而c比兩者都快一點(這是我們預期的)。

我會說出於實際目的,第一個版本比第二個更好,但如果你有很多重復鍵,3d 會是最好的。 最重要的是,理論一切都很好,但實際上最好的方法是依賴於列表的。

第一個解決方案更有效,因為它需要 O(n) 時間來完成:if 語句是 O(1),因為字典查找是 O(1)。

第二個解決方案也是 O(n) 但它運行了兩次,所以 O(n+n)。

在第一個解決方案中,您可以跳過 if 語句並直接附加 elem[0],並添加一個 try except 塊。

我認為解決方案 1解決方案 2更有效,因為它只有一個循環。 我認為您可以嘗試以下代碼,它可能比解決方案 1更有效

l = [[100, 1], [43, 2], [201, 1], [5, 7]]
d = {}
for k, v in l:
    d.setdefault(v, []).append(k)
print(d)

它給出了這樣的 o/p:

{1: [100, 201], 2: [43], 7: [5]}
l = [[100, 1], [43, 2], [201, 1], [5, 7]]
d = dict(l)
print(d)

它會給你輸出為{100: 1, 43: 2, 201: 1, 5: 7}

您的兩個解決方案將具有相同的 O( n )。 但是你可以使用collections.defaultdict

from collections import defaultdict

l = [[100, 1], [43, 2], [201, 1]]

d = defaultdict(list)

for v, k in l:
    d[k].append(v)

# defaultdict(list, {1: [100, 201], 2: [43]})

一些基准測試:

from collections import defaultdict
import numpy as np

l = np.random.randint(1, 100, [int(1e7), 2])

def dd(l):
    d = defaultdict(list)

    for i in l:
        d[i[1]].append(i[0])

    return d

def op(l):
    d = {}
    for elem in l:
        if elem[1] in d:
            d[elem[1]].append(elem[0])
        else:
            d[elem[1]] = [elem[0]]    

    return d

%timeit dd(l)  # 1 loop, best of 3: 8.22 s per loop
%timeit op(l)  # 1 loop, best of 3: 9.47 s per loop

暫無
暫無

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

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