2013-05-20 127 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我编辑我的答案上面,以减少'结果'字典到你想要的输出。 –