2013-05-20 128 views
3

我有這樣一本字典,總和在Python嵌套字典值

data={11L: [{'a': 2, 'b': 1},{'a': 2, 'b': 3}], 
22L: [{'a': 3, 'b': 2},{'a': 2, 'b': 5},{'a': 4, 'b': 2},{'a': 1, 'b': 5}, {'a': 1, 'b': 0}], 
33L: [{'a': 1, 'b': 2},{'a': 3, 'b': 5},{'a': 5, 'b': 2},{'a': 1, 'b': 3}, {'a': 1, 'b': 6},{'a':2,'b':0}], 
44L: [{'a': 4, 'b': 2},{'a': 4, 'b': 5},{'a': 3, 'b': 1},{'a': 3, 'b': 3}, {'a': 2, 'b': 3},{'a':1,'b':2},{'a': 1, 'b': 0}]} 

在這裏,我會擺脫外鍵,並賦予新的密鑰值1,2,3等等,我想得到的結果如下圖所示,

result={1:{'a':10,'b':7},2:{'a':11,'b':18},3:{'a':12,'b':5},4:{'a':5,'b':11},5:{'a':3,'b':9},6:{'a':3,'b':2},7:{'a':1,'b':0}} 

我嘗試一些像這樣的事情,但我不力獲得所需要的結果,

d = defaultdict(int) 
for dct in data.values(): 
    for k,v in dct.items(): 
    d[k] += v 
print dict(d) 

我想要結果字典的鍵是動態的,就像上面的數據字典中我們有44個最高有7個鍵值對一樣,因此我們有結果字典有7個鍵等等

+6

在字典中使用1,2和3作爲鍵意味着您可以使用列表來代替。 ;-) –

回答

5

您想在這裏使用一個列表,你想也許使用Counter()對象,使求和容易得多:

from collections import Counter 
from itertools import izip_longest 

for dcts in data.values(): 
    for i, dct in enumerate(dcts): 
     if i >= len(result): 
      result.append(Counter(dct)) 
     else: 
      result[i].update(dct) 

結果:

>>> result 
[Counter({'a': 10, 'b': 7}), Counter({'b': 18, 'a': 11}), Counter({'a': 12, 'b': 5}), Counter({'b': 11, 'a': 5}), Counter({'b': 9, 'a': 4}), Counter({'a': 3, 'b': 2}), Counter({'a': 1, 'b': 0})] 

Counter()對象是子類dict,所以他們在其他方面表現得像字典。如果您dict值之後,添加以下行:

result = [dict(r) for r in result] 

從埃裏克獲得靈感,你可以轉換到上述一個班輪:

from collections import Counter 
from itertools import izip_longest 

result = [sum(map(Counter, col), Counter()) 
    for col in izip_longest(*data.values(), fillvalue={})] 

這個版本略有不同從上面的循環中可以看出,當求和時,0的鍵被從計數器中刪除。如果你想保持'b': 0在最後的計數器,使用方法:

[reduce(lambda c, d: c.update(d) or c, col, Counter()) 
    for col in izip_longest(*data.values(), fillvalue={})] 

這再次使用.update()

+0

+1我有一個類似的第二個解決方案,除了我離開'fillvalue = {}'因爲我們要把它映射到'Counter',無論如何,唯一的是第二個不顯示'B: 0',但可能無論如何 – jamylak

+0

@jamylak:我嘗試了'{'a':0,'b':0}'的fillvalue,但是用'+'Counter'去掉了0的鍵。 '必須使用'reduce(Counter.update)'來代替這個工作。 –

2

izip_longest允許你轉置行:

from itertools import izip_longest 

print [ 
    { 
     'a': sum(cell['a'] for cell in column), 
     'b': sum(cell['b'] for cell in column) 
    } 
    for column in izip_longest(*data.values(), fillvalue={'a': 0, 'b': 0}) 
] 
[{'a': 10, 'b': 7}, {'a': 11, 'b': 18}, {'a': 12, 'b': 5}, {'a': 5, 'b': 11}, {'a': 4, 'b': 9}, {'a': 3, 'b': 2}, {'a': 1, 'b': 0}] 

或組合與計數器:

print [ 
    sum(Counter(cell) for cell in column, Counter()) 
    for column in izip_longest(*data.values(), fillvalue={}) 
] 
[Counter({'a': 10, 'b': 7}), Counter({'b': 18, 'a': 11}), Counter({'a': 12, 'b': 5}), Counter({'b': 11, 'a': 5}), Counter({'b': 9, 'a': 4}), Counter({'a': 3, 'b': 2}), Counter({'a': 1, 'b': 0})] 
0

首先發現的最長表的長度的所有值(這是列表)中:

max_length = 0 
for key in data.keys(): 
    if max_length < len(data[key]): 
     max_length = len(data[key]) 

在你的情況,max_length = 7。現在重複如下:

result = {} 
for i in range(max_length): 
    result[i+1] = {'a': 0, 'b': 0} # i + 1 since the result starts with key = 1 
    for key in data.keys(): 
     if i < len(data[key]): 
      result[i+1]['a'] += data[key][i]['a'] 
      result[i+1]['b'] += data[key][i]['b'] 

你應該得到:

print result 
{1: {'a': 10, 'b': 7}, 2: {'a': 11, 'b': 18}, 3: {'a': 12, 'b': 5}, 4: {'a': 5, 'b': 11}, 5: {'a': 4, 'b': 9}, 6: {'a': 3, 'b': 2}, 7: {'a': 1, 'b': 0}} 

編輯: @ user2286041如果您想在result字典減少到

reduced_result = {'a': [10, 11,12,5,4,3,1], 'b': [7, 18,5,11,9,2,0]} 

那麼你可以試試以下代碼:

reduced_result = {} 
inner_keys = ['a', 'b'] 
for inner_key in inner_keys: 
    temp = [] 
    for outer_key in result: 
     temp.append(result[outer_key][inner_key]) 
    reduced_result[inner_key] = temp 

我不確定如何以更通用的方式獲得inner_keys,除了明確指定它們。

+0

從上面的結果我怎麼能得到這樣的字典? {'a':[10,11,12,5,4,3,1],'b':[7,18,5,11,9,2,0]} – user2286041

+0

num = [1,2,3 ,4,5,6,7] temp1 = [result [x] ['a'] for x in num] temp2 = [result [x] ['b'] for x in num],我試過類似的東西這但每次我需要採取數字是他們的更好的方式 – user2286041

+0

@ user2286041我編輯我的答案上面,以減少'結果'字典到你想要的輸出。 –