2017-08-20 33 views
0

我有一個字典,看起來像這樣:結合類型的字典列表中,如果他們有相同的密鑰

{'Item1': [{'Name1': 3}, {'Name2': 4}, {'Name1':7}], 
'Item2': [{'Name7': 44}, {'Name2': 3}, {'Name6':9}, {'Name6':2}] 
} 

我想字典中附着在這樣關鍵的名單相結合,如果有多個類型的字典同樣的鑰匙,我可以將他們(總和)結合起來,讓其他人保持原樣。

輸出將如下所示:

{'Item1': [{'Name1': 10}, {'Name2': 4}], 
'Item2': [{'Name7': 44}, {'Name2': 3}, {'Name6': 11}] 
} 

我無法弄清楚如何在Python與列表/字典理解這樣做優雅。

+3

是否有一個原因,你有類型的字典列表?既然你想把一個鍵的多個副本摺疊成一個鍵,那麼你可能只有一個詞典。抽象地說,無論如何,你只是在笨拙地做着事情。 –

回答

0

發佈問題後幾分鐘我就想起了它。

這是我做過什麼:

from operator import add 
from collections import Counter 
results = {} 
for item, names in d.items(): 
     result[item] = (reduce(add, (Counter(name) for name in names))) 

正如上述意見和建議的答案,我最好使用1長字典,而不必到後來把幾個。不過,將答案留給任何需要它的人。

1

這使用collections.Counter。正如評論所表明的那樣,由於您輸入的結構稍微複雜 - 我可以提出最優雅的一個結構 - 一個長度的字典列表確實可以更好地實現爲單個字典。這也是我的代碼將它轉換成的東西,儘管如果你確實需要舊的數據結構,我已經提供了更多可能的轉換。如果你這樣做,我會建議使用元組作爲你的鍵值對,而不僅僅是單一長度的字典,如tuple_output所示。我建議你使用outputdict_output

from collections import Counter 

d = {'Item1': [{'Name1': 3}, {'Name2': 4}, {'Name1':7}], 'Item2': [{'Name7': 44}, {'Name2': 3}, {'Name6':9}, {'Name6':2}] } 

output = {} 
for k, v in d.items(): 
    c = Counter() 
    for sub_dict in v: 
     c.update(sub_dict) 
    output[k] = c 

dict_output = {k: dict(v) for k, v in output.items()} 
tuple_output = {k: v.most_common() for k, v in output.items()} 
dict_list_output = {k: [{a: b} for a, b in v.most_common()] for k, v in output.items()} 

print(output) 
#{'Item1': Counter({'Name1': 10, 'Name2': 4}), 'Item2': Counter({'Name7': 44, 'Name6': 11, 'Name2': 3})} 

print(dict_output) 
#{'Item1': {'Name1': 10, 'Name2': 4}, 'Item2': {'Name7': 44, 'Name2': 3, 'Name6': 11}} 

print(tuple_output) 
#{'Item1': [('Name1', 10), ('Name2', 4)], 'Item2': [('Name7', 44), ('Name6', 11), ('Name2', 3)]} 

print(dict_list_output) 
#{'Item1': [{'Name1': 10}, {'Name2': 4}], 'Item2': [{'Name7': 44}, {'Name6': 11}, {'Name2': 3}]} 

當然,如果您完全更改起始數據結構,它將變得更容易管理。如果您使用字典從字符串到計數器,可以使用計數器接口輕鬆地更新它(指link

編輯:

只是爲了好玩,在一個行來完成:

results = {item: reduce(lambda a, b: [a, a.update(b)][0], names, Counter()) for item, names in d.items()} 

它受到你的啓發,除了這隻爲每個列表構建一個Counter實例(作爲reduce的初始值給出)。此外,Counter.update已經到位,因此需要一點點高爾夫技巧才能正確減少。如果您正在閱讀本文,您可能不應該使用它,而是從一開始就使用計數器或字典構建數據結構,如前所述。

+0

感謝您展示不同方式的示例。我同意tuple_output似乎是這裏最好的方法,我正在重構我的代碼以使用它。 – boltthrower

+0

使用列表理解產生副作用是一個單線程的可怕例子。你也可以做到沒有副作用。 – AChampion

+0

我的不好。包括它可能是一個壞主意。我試圖解釋它並不打算用於嚴肅的使用,因爲在這種情況下,一個班輪可能會妨礙清晰度。你說得對。我會留給子孫後代。 –

0

也可以嘗試用defaultdict

from itertools import chain 
from collections import defaultdict 
d_new = {} 
for k, v in d.items(): 
    d_dict = defaultdict(int) 
    for k1, v1 in chain(*[ i.items() for i in v ]) : 
     d_dict[k1]+= v1 
    d_new[k] = dict(d_dict) 

print (d_new) 

輸出:

{'Item1': {'Name1': 10, 'Name2': 4}, 'Item2': {'Name7': 44, 'Name2': 3, 'Name6': 11}} 

鏈(* [我。項目(),其中i在V])將變平http://stardict.sourceforge.net/Dictionaries.php下載的列表轉換成物品

的列表轉換

[{'Name1': 3}, {'Name2': 4}, {'Name1':7}] 

[('Name1', 3), ('Name2', 4), ('Name1', 7)] 

defaultdict(int)的用於添加的值字典與相同的鍵

+0

可能更容易使用'itertools.chain.from_iterable(i.items()for i in v)'構建列表並將其解包爲'chain()'的參數。 – AChampion

1

假設你確實想要將其摺疊成一個dictlist[dict]然後你可以做到這一點,沒有任何額外的模塊與幾個簡單for循環:

In []: 
r = {} 
for k, ds in data.items(): 
    s = {} 
    for d in ds: 
     for v, c in d.items(): 
      s[v] = s.get(v, 0) + c 
    r[k] = s 
r 

Out[]: 
{'Item1': {'Name1': 10, 'Name2': 4}, 'Item2': {'Name2': 3, 'Name6': 11, 'Name7': 44}} 

由於一些似乎去爲一個套:

In []: 
import itertools as it 
from collections import Counter 

{k: dict(Counter(v for v, c in it.chain.from_iterable(d.items() for d in ds)) 
       for _ in range(c)) for k, ds in data.items()} 

Out[]: 
{'Item1': {'Name1': 10, 'Name2': 4}, 'Item2': {'Name2': 3, 'Name6': 11, 'Name7': 44}} 
相關問題