在Python中对嵌套字典的值求和

3

我有一个像这样的字典,

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作为字典的键,意味着你可以使用列表代替。;-) - Lennart Regebro
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]

受 Eric 的启发,您可以将上述内容转化为一行代码:
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()

+1 我有一个类似的第二个解决方案,只不过我留下了 fillvalue={},因为我们无论如何都会将其 mapCounter,唯一的问题是第二个解决方案在结果中没有显示 B:0,但那可能也是不必要的。 - jamylak
@jamylak:我尝试使用{'a': 0,'b': 0}的填充值,但是使用+时,Counter会消除值为0的键。我们必须使用reduce(Counter.update)才能使其起作用。 - Martijn Pieters

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,而不是明确指定它们。


从上面的结果中,我该如何得到这样一个字典? {'a': [10, 11,12,5,4,3,1], 'b': [7, 18,5,11,9,2,0]} - user2286041
num=[1,2,3,4,5,6,7] 我尝试了类似于以下的代码: temp1 = [result[x]['a'] for x in num] temp2 = [result[x]['b'] for x in num] 但每次都需要手动输入num,有没有更好的方法呢? - user2286041
@user2286041 我修改了我的答案,将 result 字典缩减为您所需的输出。 - Adler Santos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接