Вопрос-Ответ

Is there any pythonic way to combine two dicts (adding values for keys that appear in both)?

Есть ли какой-либо питонический способ объединить два dicts (добавив значения для ключей, которые появляются в обоих)?

Например, у меня есть два dicts:

Dict A: {'a': 1, 'b': 2, 'c': 3}
Dict B: {'b': 3, 'c': 4, 'd': 5}

Мне нужен pythonic способ "объединения" двух dicts таким образом, чтобы результат был:

{'a': 1, 'b': 5, 'c': 7, 'd': 5}

То есть: если ключ появляется в обоих dict, добавьте их значения, если он появляется только в одном dict, сохраните его значение.

Переведено автоматически
Ответ 1

Использовать collections.Counter:

>>> from collections import Counter
>>> A = Counter({'a':1, 'b':2, 'c':3})
>>> B = Counter({'b':3, 'c':4, 'd':5})
>>> A + B
Counter({'c': 7, 'b': 5, 'd': 5, 'a': 1})

Счетчики в основном являются подклассом dict, поэтому вы все равно можете делать с ними все остальное, что обычно делаете с этим типом, например, перебирать их ключи и значения.

Ответ 2

Более общее решение, которое работает и для нечисловых значений:

a = {'a': 'foo', 'b':'bar', 'c': 'baz'}
b = {'a': 'spam', 'c':'ham', 'x': 'blah'}

r = dict(a.items() + b.items() +
[(k, a[k] + b[k]) for k in set(b) & set(a)])

или даже более общий:

def combine_dicts(a, b, op=operator.add):
return dict(a.items() + b.items() +
[(k, op(a[k], b[k])) for k in set(b) & set(a)])

Например:

>>> a = {'a': 2, 'b':3, 'c':4}
>>> b = {'a': 5, 'c':6, 'x':7}

>>> import operator
>>> print combine_dicts(a, b, operator.mul)
{'a': 10, 'x': 7, 'c': 24, 'b': 3}
Ответ 3
>>> A = {'a':1, 'b':2, 'c':3}
>>> B = {'b':3, 'c':4, 'd':5}
>>> c = {x: A.get(x, 0) + B.get(x, 0) for x in set(A).union(B)}
>>> print(c)

{'a': 1, 'c': 7, 'b': 5, 'd': 5}
Ответ 4

Вступление: Есть (вероятно) лучшие решения. Но вы должны это знать и помнить, а иногда вам приходится надеяться, что ваша версия Python не слишком старая или в чем бы там ни заключалась проблема.

Тогда есть самые "хакерские" решения. Они замечательные и короткие, но иногда их трудно понять, прочитать и запомнить.

Однако есть альтернатива, которая заключается в попытке изобрести велосипед. - Зачем изобретать велосипед? - Обычно потому, что это действительно хороший способ обучения (а иногда просто потому, что уже существующий инструмент делает не совсем то, что вам хотелось бы и / или так, как вам хотелось бы) и самый простой способ, если вы не знаете или не помните идеальный инструмент для вашей проблемы.

Итак, я предлагаю заново изобрести колесо для Counter класса из collections модуля (по крайней мере, частично):

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}

Вероятно, есть и другие способы реализовать это, и уже есть инструменты для этого, но всегда приятно представить, как все будет работать в принципе.

python dictionary