By Derrick Zhang


2012-06-13 09:17:28 8 Comments

For example I have two dicts:

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

I need a pythonic way of 'combining' two dicts such that the result is:

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

That is to say: if a key appears in both dicts, add their values, if it appears in only one dict, keep its value.

18 comments

@Adeel 2014-07-04 10:49:33

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

Alternative you can use Counter as @Martijn has mentioned above.

@Giovanni Gianni 2016-08-28 09:47:37

From python 3.5: merging and summing

Thanks to @tokeinizer_fsj that told me in a comment that I didn't get completely the meaning of the question (I thought that add meant just adding keys that eventually where different in the two dictinaries and, instead, i meant that the common key values should be summed). So I added that loop before the merging, so that the second dictionary contains the sum of the common keys. The last dictionary will be the one whose values will last in the new dictionary that is the result of the merging of the two, so I thing the problem is solved. The solution is valid from python 3.5 and following versions.

a = {
    "a": 1,
    "b": 2,
    "c": 3
}

b = {
    "a": 2,
    "b": 3,
    "d": 5
}

# Python 3.5

for key in b:
    if key in a:
        b[key] = b[key] + a[key]

c = {**a, **b}
print(c)

>>> c
{'a': 3, 'b': 5, 'c': 3, 'd': 5}

Reusable code

a = {'a': 1, 'b': 2, 'c': 3}
b = {'b': 3, 'c': 4, 'd': 5}


def mergsum(a, b):
    for k in b:
        if k in a:
            b[k] = b[k] + a[k]
    c = {**a, **b}
    return c


print(mergsum(a, b))

@tokenizer_fsj 2018-07-07 17:02:40

This way of merging dictionaries it's not adding the values for common keys. In the question, the desired value for key b is 5 (2+3), but your method is returning 3.

@Giovanni Gianni 2018-07-08 03:51:55

@tokenizer_fsj you are right, I'm gonna fix it now

@Lacobus 2018-06-12 17:45:22

What about:

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 ) )

Output:

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

@user6830669 2017-11-17 09:18:43

Merging three dicts a,b,c in a single line without any other modules or libs

If we have the three dicts

a = {"a":9}
b = {"b":7}
c = {'b': 2, 'd': 90}

Merge all with a single line and return a dict object using

c = dict(a.items() + b.items() + c.items())

Returning

{'a': 9, 'b': 2, 'd': 90}

@Patrick Mevzek 2018-02-14 19:13:53

Reread the question, this is not the expected output. It should have been with your inputs: {'a': 9, 'b': 9, 'd': 90}. You are missing the "sum" requirement.

@shouldsee 2017-08-20 15:11:52

Additionally, please note a.update( b ) is 2x faster than a + b

from collections import Counter
a = Counter({'menu': 20, 'good': 15, 'happy': 10, 'bar': 5})
b = Counter({'menu': 1, 'good': 1, 'bar': 3})

%timeit a + b;
## 100000 loops, best of 3: 8.62 µs per loop
## The slowest run took 4.04 times longer than the fastest. This could mean that an intermediate result is being cached.

%timeit a.update(b)
## 100000 loops, best of 3: 4.51 µs per loop

@Devesh Saini 2014-05-03 06:20:57

The one with no extra imports!

Their is a pythonic standard called EAFP(Easier to Ask for Forgiveness than Permission). Below code is based on that python standard.

# The A and B dictionaries
A = {'a': 1, 'b': 2, 'c': 3}
B = {'b': 3, 'c': 4, 'd': 5}

# The final dictionary. Will contain the final outputs.
newdict = {}

# Make sure every key of A and B get into the final dictionary 'newdict'.
newdict.update(A)
newdict.update(B)

# Iterate through each key of A.
for i in A.keys():

    # If same key exist on B, its values from A and B will add together and
    # get included in the final dictionary 'newdict'.
    try:
        addition = A[i] + B[i]
        newdict[i] = addition

    # If current key does not exist in dictionary B, it will give a KeyError,
    # catch it and continue looping.
    except KeyError:
        continue

EDIT: thanks to jerzyk for his improvement suggestions.

@Joop 2014-09-11 09:03:16

n^2 algorith will be significantly slower than Counter method

@nom-mon-ir 2015-06-27 05:09:54

+like this simple method, no need to import extra

@Jerzyk 2016-06-08 04:51:13

are you sure, that B['d'] will manage to get to the newdict? (p.s. variables in python should be small-caps)

@Devesh Saini 2016-06-10 07:07:28

Just edited, it works now. thanks for review. @Jerzyk

@Jerzyk 2016-06-10 08:50:41

@DeveshSaini better, but still sub-optimal :) e.g: do you really need sorting? and then, why two loops? you already have all keys in the newdict, just small hints to optimize

@Devesh Saini 2016-07-21 13:50:52

second edition, thanks @Jerzyk

@Devesh Saini 2016-07-21 13:52:45

n^1 algorithm has been placed instead of previous n^2 algorithm @Joop

@Michael Hall 2017-08-01 04:58:16

The above solutions are great for the scenario where you have a small number of Counters. If you have a big list of them though, something like this is much nicer:

from collections import Counter

A = Counter({'a':1, 'b':2, 'c':3})
B = Counter({'b':3, 'c':4, 'd':5}) 
C = Counter({'a': 5, 'e':3})
list_of_counts = [A, B, C]

total = sum(list_of_counts, Counter())

print(total)
# Counter({'c': 7, 'a': 6, 'b': 5, 'd': 5, 'e': 3})

The above solution is essentially summing the Counters by:

total = Counter()
for count in list_of_counts:
    total += count
print(total)
# Counter({'c': 7, 'a': 6, 'b': 5, 'd': 5, 'e': 3})

This does the same thing but I think it always helps to see what it is effectively doing underneath.

@citizen2077 2017-06-28 21:31:40

This is a simple solution for merging two dictionaries where += can be applied to the values, it has to iterate over a dictionary only once, I'm surprised no one has suggested this

a = {'a':1, 'b':2, 'c':3}

dicts = [{'b':3, 'c':4, 'd':5},
         {'c':9, 'a':9, 'd':9}]

def merge_dicts(merged,mergedfrom):
    for k,v in mergedfrom.items():
        if k in merged:
            merged[k] += v
        else:
            merged[k] = v
    return merged

for dct in dicts:
    a = merge_dicts(a,dct)
print (a)
#{'c': 16, 'b': 5, 'd': 14, 'a': 10}

@Kasrâmvd 2017-03-10 11:12:15

Definitely summing the Counter()s is the most pythonic way to go in such cases but only if it results in a positive value. Here is an example and as you can see there is no c in result after negating the c's value in B dictionary.

In [1]: from collections import Counter

In [2]: A = Counter({'a':1, 'b':2, 'c':3})

In [3]: B = Counter({'b':3, 'c':-4, 'd':5})

In [4]: A + B
Out[4]: Counter({'d': 5, 'b': 5, 'a': 1})

That's because Counters were primarily designed to work with positive integers to represent running counts (negative count is meaningless). But to help with those use cases,python documents the minimum range and type restrictions as follows:

  • The Counter class itself is a dictionary subclass with no restrictions on its keys and values. The values are intended to be numbers representing counts, but you could store anything in the value field.
  • The most_common() method requires only that the values be orderable.
  • For in-place operations such as c[key] += 1, the value type need only support addition and subtraction. So fractions, floats, and decimals would work and negative values are supported. The same is also true for update() and subtract() which allow negative and zero values for both inputs and outputs.
  • The multiset methods are designed only for use cases with positive values. The inputs may be negative or zero, but only outputs with positive values are created. There are no type restrictions, but the value type needs to support addition, subtraction, and comparison.
  • The elements() method requires integer counts. It ignores zero and negative counts.

So for getting around that problem after summing your Counter you can use Counter.update in order to get the desire output. It works like dict.update() but adds counts instead of replacing them.

In [24]: A.update(B)

In [25]: A
Out[25]: Counter({'d': 5, 'b': 5, 'a': 1, 'c': -1})

@riders994 2017-03-21 17:15:49

Much better than accepted answer. Thanks!

@tsabi 2017-01-18 17:14:40

The best to use is dict():

A = {'a':1, 'b':2, 'c':3}
B = {'b':3, 'c':4, 'd':5}
Merged = dict(A, **B)
Merged == {'a':1, 'b':3, 'c':3, 'd':5}

@Daisy 2017-01-19 19:18:00

it does not sum the values

@Ignacio Villela 2016-12-09 14:26:10

This solution is easy to use, it is used as a normal dictionary, but you can use the sum function.

class SumDict(dict):
    def __add__(self, y):
        return {x: self.get(x, 0) + y.get(x, 0) for x in set(self).union(y)}

A = SumDict({'a': 1, 'c': 2})
B = SumDict({'b': 3, 'c': 4})  # Also works: B = {'b': 3, 'c': 4}
print(A + B)  # OUTPUT {'a': 1, 'b': 3, 'c': 6}

@Jonas Kölker 2016-06-10 13:11:05

def merge_with(f, xs, ys):
    xs = a_copy_of(xs) # dict(xs), maybe generalizable?
    for (y, v) in ys.iteritems():
        xs[y] = v if y not in xs else f(xs[x], v)

merge_with((lambda x, y: x + y), A, B)

You could easily generalize this:

def merge_dicts(f, *dicts):
    result = {}
    for d in dicts:
        for (k, v) in d.iteritems():
            result[k] = v if k not in result else f(result[k], v)

Then it can take any number of dicts.

@georg 2012-06-13 09:41:10

A more generic solution, which works for non-numeric values as well:

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)])

or even more generic:

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)])

For example:

>>> 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}

@Martijn Pieters 2012-06-13 10:32:08

You could also use for k in b.viewkeys() & a.viewkeys(), when using python 2.7, and skip the creation of sets.

@Hai Phan 2017-04-01 20:34:10

Why does set(a) return the set of keys rather set of tuples? What's the rationale for this?

@georg 2017-04-01 22:05:41

@HaiPhan: because dicts iterate over keys, not over kv-pairs. cf list({..}), for k in {...} etc

@Craicerjack 2017-08-15 14:48:18

I know this is old but the final line of this seems to multiply the values and not add them as OP wanted...

@georg 2017-08-15 15:07:19

@Craicerjack: yep, I used operator.mul to make clear that this code is generic and not limited to adding numbers.

@Craicerjack 2017-08-15 15:17:37

@georg i completely misread that. thanks.

@vaultah 2017-11-12 21:44:19

Could you add a Python 3-compatible option? {**a, **b, **{k: op(a[k], b[k]) for k in a.keys() & b}} should work in Python 3.5+.

@JeromeJ 2013-02-18 06:45:45

Intro: There are the (probably) best solutions. But you have to know it and remember it and sometimes you have to hope that your Python version isn't too old or whatever the issue could be.

Then there are the most 'hacky' solutions. They are great and short but sometimes are hard to understand, to read and to remember.

There is, though, an alternative which is to to try to reinvent the wheel. - Why reinventing the wheel? - Generally because it's a really good way to learn (and sometimes just because the already-existing tool doesn't do exactly what you would like and/or the way you would like it) and the easiest way if you don't know or don't remember the perfect tool for your problem.

So, I propose to reinvent the wheel of the Counter class from the collections module (partially at least):

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}

There would probably others way to implement that and there are already tools to do that but it's always nice to visualize how things would basically works.

@Brian B 2013-02-22 19:30:53

Nice for those of us still on 2.6 also

@schettino72 2014-11-14 10:43:41

For a more generic and extensible way check mergedict. It uses singledispatch and can merge values based on its types.

Example:

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'}

@Martijn Pieters 2012-06-13 09:22:27

Use 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})

Counters are basically a subclass of dict, so you can still do everything else with them you'd normally do with that type, such as iterate over their keys and values.

@Jan-Philip Gehrcke 2015-01-22 20:57:58

What of there are multiple Counters to merge like this? sum(counters) does not work, unfortunately.

@Martijn Pieters 2015-01-22 21:07:43

@Jan-PhilipGehrcke: Give sum() a starting value, with sum(counters, Counter()).

@Jan-Philip Gehrcke 2015-01-22 21:22:16

Thanks. However, this method is affected by intermediate-object-creation as summing strings is, right?

@Martijn Pieters 2015-01-22 21:42:29

@Jan-PhilipGehrcke: Your other option is to use a loop and += to do in-place summing. res = counters[0], then for c in counters[1:]: res += c.

@Jan-Philip Gehrcke 2015-01-22 21:51:54

I like that approach! If someone likes keep things close to processing dictionaries, one could also use update() instead of +=: for c in counters[1:]: res.update(c).

@Sudipta Basak 2015-05-19 13:44:44

Thanks so much. This seems to be the only elegant (not considering performance, least lines) solution in python 2.

@user1767754 2015-06-15 21:21:43

What when i have not two but multiple (100 Dicts), which are in a list, is there an elaborate way?

@Pyderman 2015-07-05 01:34:19

@MartijnPieters see stackoverflow.com/questions/31226485/… here for where this almost works but breaks down when the sum of values for a given key is 0.

@Martijn Pieters 2015-07-05 01:37:52

@Pyderman: Use Counter.update() if you don't want to drop the 0 values; e.g. C = A.copy(); C.update(B). See combining two python dictionaries into one when the net values are not positive

@Pyderman 2015-07-05 01:49:53

@MartijnPieters For your almost Rainmain-like memory of duplicates, and for sticking with my remonstrations until I was presented with a solution, I thank you.

@Eric Wang 2016-09-13 07:48:08

Counter only works for positive int or float

@Martijn Pieters 2016-09-13 08:17:07

@EricWang: That's demonstrably not true. from the documentation: Counts are allowed to be any integer value including zero or negative counts. and Several mathematical operations are provided for combining Counter objects to produce multisets (counters that have counts greater than zero). [...] Each operation can accept inputs with signed counts, but the output will exclude results with counts of zero or less.

@Martijn Pieters 2016-09-13 08:17:30

@EricWang: also read the section starting with Note: Counters were primarily designed to work with positive integers to represent running counts; however, care was taken to not unnecessarily preclude use cases needing other types or negative values. So certain operations only work with positive integers, but negative integers and floats are not outside the scope of Counter objects otherwise.

@user3804919 2014-07-04 10:06:27

myDict = {}
for k in itertools.chain(A.keys(), B.keys()):
    myDict[k] = A.get(k, 0)+B.get(k, 0)

@Ashwini Chaudhary 2012-06-13 09:25:28

>>> 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}

@Martijn Pieters 2012-06-13 10:29:12

set(A) is the same as set(A.keys()), so you can drop the call to .keys().

@Joel Cornett 2012-06-13 10:42:30

... and in python 2.x, doing set(A) is marginally faster than doing set(A.keys()) because you avoid creating the extra sequence produced by the call to keys() (using set(A) just causes A to return an iterator object to set()).

@JeromeJ 2013-02-18 06:58:03

Wouldn't using for x in set(itertools.chain(A, B)) be more logical? As using set on dict is a bit of a nonsense as keys are already unique? I know it's just another way to get a set of the keys but I find it more confusing than using itertools.chain (implying you know what itertools.chain does)

@gsamaras 2016-02-09 19:03:32

That should be the top answer.

Related Questions

Sponsored Content

42 Answered Questions

[SOLVED] How do I sort a dictionary by value?

43 Answered Questions

[SOLVED] How to merge two dictionaries in a single expression?

9 Answered Questions

18 Answered Questions

[SOLVED] How do you sort a dictionary by value?

57 Answered Questions

[SOLVED] How do you split a list into evenly sized chunks?

19 Answered Questions

[SOLVED] Pythonic way to create a long multi-line string

10 Answered Questions

[SOLVED] Calling a function of a module by using its name (a string)

  • 2008-08-06 03:36:08
  • ricree
  • 551583 View
  • 1380 Score
  • 10 Answer
  • Tags:   python object

8 Answered Questions

[SOLVED] How to iterate through two lists in parallel?

  • 2009-11-02 21:26:24
  • Nathan Fellman
  • 480203 View
  • 663 Score
  • 8 Answer
  • Tags:   python iterator

10 Answered Questions

[SOLVED] What are "named tuples" in Python?

22 Answered Questions

[SOLVED] Calculate difference in keys contained in two Python dictionaries

  • 2009-07-22 13:43:13
  • Bhaskar
  • 140176 View
  • 158 Score
  • 22 Answer
  • Tags:   python dictionary

Sponsored Content