多个Python字典中对应元素求和

9

我有一些等长的Python字典,它们具有匹配的键集,就像这样:

{'a':1, 'b':4, 'c':8, 'd':9}

{'a':2, 'b':3, 'c':2, 'd':7}

{'a':0, 'b':1, 'c':3, 'd':4}
...

我该如何获得一个单一的字典,它具有相同的键集,但值为字典集中对应元素之和?换句话说,我想要:
```python {'a': 6, 'b': 8, 'c': 10} ```
给定以下字典集合:
```python [{'a': 1, 'b': 2, 'c': 3}, {'a': 5, 'b': 6, 'c': 7}] ```
{'a':3, 'b':8, 'c':13, 'd':20}

也许有一种丑陋、复杂的循环结构,但是有没有更好的方法来使用某种列表/字典推导技巧呢?说起来,我真不确定如何制作一个丑陋的循环版本..

原始字典存在哪里?它们都有单独的名称吗?还是存在于一个字典集合或数组中? - lurker
它们在一个更大的总字典中按ID编号索引。我想能够对某些可变大小的子集求和(例如,键为1、5、34和67的子集)。 - norman
如果您创建一个字典列表,例如DList = [d[1], d[5], d[34], d[67]],则仍然可以使用@TimPeters的答案和您的ID号码(如果您的ID号码在该列表中)。 (如果您在网站上搜索有关从指定元素创建列表的内容,则还有其他以编程方式生成该列表的方法...) - beroe
也许是一个愚蠢的问题,但如果我有一个字典的字典,这个方法还有效吗?类似这样:for id_num in cluster: c.update(overall_dict[id_num]) - norman
4个回答

30

collections.Counter() 来救场 ;-)

from collections import Counter
dicts = [{'a':1, 'b':4, 'c':8, 'd':9},
         {'a':2, 'b':3, 'c':2, 'd':7},
         {'a':0, 'b':1, 'c':3, 'd':4}]
c = Counter()
for d in dicts:
    c.update(d)

然后:

>>> print c
Counter({'d': 20, 'c': 13, 'b': 8, 'a': 3})

或者你可以将它转回字典:

>>> print dict(c)
{'a': 3, 'c': 13, 'b': 8, 'd': 20}

Counter()并不关心所有输入字典是否具有相同的键。如果您确定它们是相同的,则可以尝试荒谬的一行代码,例如:

d = {k: v for k in dicts[0] for v in [sum(d[k] for d in dicts)]}

Counter()更清晰、更快速和更灵活。但公平地说,这个稍微不那么可笑的一行代码也没那么可笑:

d = {k: sum(d[k] for d in dicts) for k in dicts[0]}

不错。我喜欢你的“不那么荒谬”的版本,但如果你使用除了d以外的其他东西作为目标字典,可能会更清晰。 - beroe
@beroe,但这会让它变得更不可思议!;-) - Tim Peters
抱歉,我的错!我以为那是[递归]的重点... :^) - beroe

6
如果您只是想使用dict,您可以使用这个。
dicts = [{'a':0, 'b':4, 'c':8, 'd':9},
         {'a':0, 'b':3, 'c':2, 'd':7},
         {'a':0, 'b':1, 'c':3, 'd':4}]

result = {}
for myDict in dicts:
    for key, value in myDict.items():
        result.setdefault(key, 0)
        result[key] += value
print result

输出:

{'a': 0, 'c': 13, 'b': 8, 'd': 20}

0
一条使用sentinel值将sum作为Counter对象的单行代码:
>>> from collections import Counter
>>> dicts = [{'a':1, 'b':4, 'c':8, 'd':9},
         {'a':2, 'b':3, 'c':2, 'd':7},
         {'a':0, 'b':1, 'c':3, 'd':4}]
>>> dict(sum(map(Counter, dicts), start=Counter()))
{'a': 3, 'b': 8, 'c': 13, 'd': 20}

-1

这里提供了一种使用字典推导式的替代方法,使用 itertools.chain.from_iterable()sum()

在这里,我创建了一个包含所有三个字典键的set。然后我在字典推导式中迭代这个集合,以获取每个之和。

from itertools import chain

my_dicts = [
    {'a':1, 'b':4, 'c':8, 'd':9},
    {'a':2, 'b':3, 'c':2, 'd':7},
    {'a':0, 'b':1, 'c':3, 'd':4}
]
    
new_dict = {k: sum(dd.get(k, 0) for dd in my_dicts) for k in set(chain.from_iterable(d.keys() for d in my_dicts))}

# where `new_dict` will hold:
#   {
#      'a': 3,  
#      'b': 8,
#      'c': 13,
#      'd': 20
#   }

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