views:

1547

answers:

4

Hello,

My input is two dictionaries that have string keys and integer values. I want to add the two dictionaries so that the result has all the keys of the input dictionaries, and the values are the sum of the input dictionaries' values.

For clarity, if a key appears in only one of the inputs, that key/value will appear in the result, whereas if the key appears in both dictionaries, the sum of values will appear in the result.

For example, say my input is:

a = dict()
a['cat'] = 1
a['fish'] = 10
a['aardvark'] = 1000

b = dict()
b['cat'] = 2
b['dog'] = 200
b['aardvark'] = 2000

I would like the result to be:

{'cat': 3, 'fish': 10, 'dog': 200, 'aardvark': 3000}

Knowing Python there must be a one-liner to get this done (it doesn't really have to be one line...). Any thoughts?

+14  A: 

result in a:

for elem in b:
    a[elem] = a.get(elem, 0) + b[elem]

result in c:

c = dict(a)
for elem in b:
    c[elem] = a.get(elem, 0) + b[elem]
Adrian Panasiuk
These are two lines btw :)
Aamir
Not a one-liner, but the easiest to read. +1
musicfreak
+18  A: 

How about that:

dict( [ (n, a.get(n, 0)+b.get(n, 0)) for n in set(a)|set(b) ] )

Or without creating an intermediate list (generator is enough):

dict( (n, a.get(n, 0)+b.get(n, 0)) for n in set(a)|set(b) )
Juergen
+1 nice, although the square brackets aren't necessary as dict() will take a generator
cobbal
Thats right! Just a habit of me. I saw it afterwards.
Juergen
+1: nice one-liner. However, I'd do set(a).union(b), so as not to create an intermediate set [set(b)].
EOL
@EOL: Thanks, thats right. There is always a way to squeeze out a little more ...
Juergen
+7  A: 

Not in one line, but ...

import itertools
import collections
a = dict()
a['cat'] = 1
a['fish'] = 10
a['aardvark'] = 1000
b = dict()
b['cat'] = 2
b['dog'] = 200
b['aardvark'] = 2000
c = collections.defaultdict(int)
for k, v in itertools.chain(a.iteritems(), b.iteritems()):
    c[k] += v

You can easily extend it to a larger number of dictionaries.

unbeknown
itertools.chain is a nice solution, when maximum speed is needed, since in my solution a temporary set is created. I suppose, chain is faster for big dicts.
Juergen
Well, I didn't use it for speed here. I just don't need to check if there are elements from a that are missing in b and vice versa.
unbeknown
+1  A: 

One liner (as sortof requested): get key lists, add them, discard duplicates, iterate over result with list comprehension, return (key,value) pairs for the sum if the key is in both dicts, or just the individual values if not. Wrap in dict.

>>> dict([(x,a[x]+b[x]) if (x in a and x in b) else (x,a[x]) if (x in a) else (x,b[x]) for x in set(a.keys()+b.keys())])
{'aardvark': 3000, 'fish': 10, 'dog': 200, 'cat': 3}
Markus