3

I have two Python dictionaries, and I want to merge (union) them together but with a custom update function in case the same key exists in both dicts. For instance:

>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = {'a': 3, 'd': 5}
>>> merge(x,y,z)  # add values together if key exists in both
{'a': 4, 'b': 12, 'c': 11, 'd': 5}

What's the simplest way to do so?

Edit: I'm looking for a solution that works for arbitrary number of dicts to merge, and perform arbitrary operation when the same key is in more than 1 dict (not necessarily add).

JRR
  • 6,014
  • 6
  • 39
  • 59
  • 1
    [Check this out](https://stackoverflow.com/questions/11011756/is-there-any-pythonic-way-to-combine-two-dicts-adding-values-for-keys-that-appe) –  Jun 18 '21 at 04:17
  • Using `collections.Counter`, you can convert dictionaries to Counter objects, add them and then recast the result as dictionary. – Zoro Jun 18 '21 at 04:19
  • 1
    Does this answer your question? [Is there any pythonic way to combine two dicts (adding values for keys that appear in both)?](https://stackoverflow.com/questions/11011756/is-there-any-pythonic-way-to-combine-two-dicts-adding-values-for-keys-that-appe) – Stuti Rastogi Jun 18 '21 at 04:22

2 Answers2

3

Use collections.Counter. It will help you.

from collections import Counter
A = Counter({'a': 1, 'b': 2})
B = Counter({'b': 10, 'c': 11})
print(dict(A+B))

Output

{'a': 1, 'b': 12, 'c': 11}
1

Get the union of all the keys in both the dictionary, and just add values from both the dictionary using dict.get() with default value as 0, you can use dictionary-comprehension.

def merge(d1, d2):
    keys = set(d1.keys()).union(d2.keys())
    return {k: d1.get(k,0)+d2.get(k,0) for k in keys}

OUTPUT:

>>> merge(x, y)
{'c': 11, 'a': 1, 'b': 12}

SPEED COMPARISON (>4X Faster):

using merge (custom function): 
2.99 µs ± 574 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

using Counter: 
14.2 µs ± 709 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

After UPDATE to the question :

You can just modify the function a bit using *args if you want to do it for any number of dictionaryies:

def merge(*args):
    keys = set()
    for arg in args:
        keys = keys.union(arg.keys())
    return {k: sum(arg.get(k,0) for arg in args) for k in keys}

OUTPUT:

>>> merge(x, y, z)
{'a': 4, 'd': 5, 'c': 11, 'b': 12}
ThePyGuy
  • 17,779
  • 5
  • 18
  • 45