例如,我有两个字典:
Dict A: {'a': 1, 'b': 2, 'c': 3}
Dict B: {'b': 3, 'c': 4, 'd': 5}
我需要一种python的方式来“组合”两个字典,这样的结果是:
{'a': 1, 'b': 5, 'c': 7, 'd': 5}
也就是说:如果一个键在两个字典中都出现,则将它们的值相加,如果它只在一个字典中出现,则保留其值。
例如,我有两个字典:
Dict A: {'a': 1, 'b': 2, 'c': 3}
Dict B: {'b': 3, 'c': 4, 'd': 5}
我需要一种python的方式来“组合”两个字典,这样的结果是:
{'a': 1, 'b': 5, 'c': 7, 'd': 5}
也就是说:如果一个键在两个字典中都出现,则将它们的值相加,如果它只在一个字典中出现,则保留其值。
当前回答
人物介绍: 有(可能)最好的解决方案。但你必须知道并记住它,有时你必须希望你的Python版本不是太旧或其他问题。
还有一些最“俗气”的解决方案。它们伟大而简短,但有时却很难理解、阅读和记忆。
不过,还有另一种选择,那就是尝试重新发明轮子。 -为什么要重新发明轮子? -一般来说,这是一个很好的学习方法(有时只是因为现有的工具不能完全按照你想要的方式来做),如果你不知道或不记得解决你的问题的完美工具,这是最简单的方法。
因此,我建议从collections模块重新发明Counter类的轮子(至少部分地):
class MyDict(dict):
def __add__(self, oth):
r = self.copy()
try:
for key, val in oth.items():
if key in r:
r[key] += val # You can custom it here
else:
r[key] = val
except AttributeError: # In case oth isn't a dict
return NotImplemented # The convention when a case isn't handled
return r
a = MyDict({'a':1, 'b':2, 'c':3})
b = MyDict({'b':3, 'c':4, 'd':5})
print(a+b) # Output {'a':1, 'b': 5, 'c': 7, 'd': 5}
可能还有其他的方法来实现它,而且已经有工具可以做到这一点,但是把事情的基本原理可视化总是很好的。
其他回答
要获得更通用和可扩展的方法,请检查mergedict。它使用singledispatch,并可以根据类型合并值。
例子:
from mergedict import MergeDict
class SumDict(MergeDict):
@MergeDict.dispatch(int)
def merge_int(this, other):
return this + other
d2 = SumDict({'a': 1, 'b': 'one'})
d2.merge({'a':2, 'b': 'two'})
assert d2 == {'a': 3, 'b': 'two'}
import itertools
import collections
dictA = {'a':1, 'b':2, 'c':3}
dictB = {'b':3, 'c':4, 'd':5}
new_dict = collections.defaultdict(int)
# use dict.items() instead of dict.iteritems() for Python3
for k, v in itertools.chain(dictA.iteritems(), dictB.iteritems()):
new_dict[k] += v
print dict(new_dict)
# OUTPUT
{'a': 1, 'c': 7, 'b': 5, 'd': 5}
OR
你也可以像@Martijn上面提到的那样使用Counter。
这是一个很一般的解。你可以处理任意数量的dict +键,只在一些dict +容易使用任何聚合函数你想要:
def aggregate_dicts(dicts, operation=sum):
"""Aggregate a sequence of dictionaries using `operation`."""
all_keys = set().union(*[el.keys() for el in dicts])
return {k: operation([dic.get(k, None) for dic in dicts]) for k in all_keys}
例子:
dicts_same_keys = [{'x': 0, 'y': 1}, {'x': 1, 'y': 2}, {'x': 2, 'y': 3}]
aggregate_dicts(dicts_same_keys, operation=sum)
#{'x': 3, 'y': 6}
不相同的键和泛型聚合示例:
dicts_diff_keys = [{'x': 0, 'y': 1}, {'x': 1, 'y': 2}, {'x': 2, 'y': 3, 'c': 4}]
def mean_no_none(l):
l_no_none = [el for el in l if el is not None]
return sum(l_no_none) / len(l_no_none)
aggregate_dicts(dicts_diff_keys, operation=mean_no_none)
# {'x': 1.0, 'c': 4.0, 'y': 2.0}
人物介绍: 有(可能)最好的解决方案。但你必须知道并记住它,有时你必须希望你的Python版本不是太旧或其他问题。
还有一些最“俗气”的解决方案。它们伟大而简短,但有时却很难理解、阅读和记忆。
不过,还有另一种选择,那就是尝试重新发明轮子。 -为什么要重新发明轮子? -一般来说,这是一个很好的学习方法(有时只是因为现有的工具不能完全按照你想要的方式来做),如果你不知道或不记得解决你的问题的完美工具,这是最简单的方法。
因此,我建议从collections模块重新发明Counter类的轮子(至少部分地):
class MyDict(dict):
def __add__(self, oth):
r = self.copy()
try:
for key, val in oth.items():
if key in r:
r[key] += val # You can custom it here
else:
r[key] = val
except AttributeError: # In case oth isn't a dict
return NotImplemented # The convention when a case isn't handled
return r
a = MyDict({'a':1, 'b':2, 'c':3})
b = MyDict({'b':3, 'c':4, 'd':5})
print(a+b) # Output {'a':1, 'b': 5, 'c': 7, 'd': 5}
可能还有其他的方法来实现它,而且已经有工具可以做到这一点,但是把事情的基本原理可视化总是很好的。
是什么:
def dict_merge_and_sum( d1, d2 ):
ret = d1
ret.update({ k:v + d2[k] for k,v in d1.items() if k in d2 })
ret.update({ k:v for k,v in d2.items() if k not in d1 })
return ret
A = {'a': 1, 'b': 2, 'c': 3}
B = {'b': 3, 'c': 4, 'd': 5}
print( dict_merge_and_sum( A, B ) )
输出:
{'d': 5, 'a': 1, 'c': 7, 'b': 5}