3


I have two dictionaries:

d1 = {'a':('x','y'),'b':('k','l')}
d2 = {'a':('m','n'),'c':('p','r')}

How do I merge these two dictionaries to get such result:

d3 = {'a':('x','y','m','n'),'b':('k','l'),'c':('p','r')}

This works when values of the dictionary are simple type like int or str:

d3 = dict([(i,a[i]+b[i]) for i in set(a.keys()+b.keys())])

But I have no idea how deal with lists as values...

Notice: my question is different to How to merge two Python dictionaries in a single expression? cause I don't want to update values but add them

Community
  • 1
  • 1
psmith
  • 1,769
  • 5
  • 35
  • 60
  • 1
    Possible duplicate. This should answer your question: http://stackoverflow.com/questions/38987/how-can-i-merge-two-python-dictionaries-in-a-single-expression –  Jun 27 '15 at 21:24
  • 2
    @gargas I don't think it's a duplicate. The question you referenced is a last-one-wins, not a value merge. – Ami Tavory Jun 27 '15 at 21:32

4 Answers4

3

Your question is a little bit mangled with respect to variable names, but I think this does what you want:

d3 = dict([(i,d1.get(i,())+d2.get(i,())) for i in set(d1.keys()+d2.keys())])
d3
{'a': ('x', 'y', 'm', 'n'), 'b': ('k', 'l'), 'c': ('p', 'r')}

Note that you can add (ie extend) lists and tuples with +.

Gringo Suave
  • 29,931
  • 6
  • 88
  • 75
xnx
  • 24,509
  • 11
  • 70
  • 109
1

There's no problem with adding lists in Python (it concatenates them); there's a bit of a problem deciding when to add, though, as it should be done only when the key appears in both dictionaries.

d3 = dict(
    [(i, d1[i]+d2[i]) for i in set(d1.keys()).intersection(d2.keys())] +\
    [(i, d1[i]) for i in set(d1.keys()) - set(d2.keys())] +\
    [(i, d2[i]) for i in set(d2.keys()) - set(d1.keys())])
>> d3
{'a': ('x', 'y', 'm', 'n'), 'b': ('k', 'l'), 'c': ('p', 'r')}
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
1

Two things:

  1. You can just add lists and tuples, that should work.

    In [5]: ('x','y') + ('m','n')

    Out[5]: ('x', 'y', 'm', 'n')

  2. d3 = dict([(i,a[i]+b[i]) for i in set(a.keys()+b.keys())]) fails in any case where a key only shows up in a or b but not both. Values are irrelevant here.

Personally, I'd go with something like:

d3 = {}

for i in set(a.keys()+b.keys()):
    val1 = a[i] if i in a else ()
    val2 = b[i] if i in b else ()
    d3[i] = val1+val2
NightShadeQueen
  • 3,284
  • 3
  • 24
  • 37
1

You could use dict.viewitems with a for loop:

d1 = {'a': ('x', 'y'), 'b': ('k', 'l')}
d2 = {'a': ('m', 'n'), 'c': ('p', 'r')}

d3 = {}

for key, item in d1.viewitems() | d2.viewitems():
    d3[key]= d3.get(key,()) + item

print(d3)

{'a': ('x', 'y', 'm', 'n'), 'c': ('p', 'r'), 'b': ('k', 'l')}

Or use a defaultdict:

from collections import defaultdict
d3 = defaultdict(tuple)
for key, item in d1.viewitems() | d2.viewitems():
    d3[key] += item

print(d3)

Or use viewkeys for your lists as they are not hashable:

d1 = {'a': ['x', 'y'], 'b': ['k', 'l']}
d2 = {'a': ['m', 'n'], 'c': ['p', 'r']}


d3 = {}

for key in d1.viewkeys() | d2.viewkeys():
    d3[key] = d1.get(key, []) + d2.get(key, [])

print(d3)

Which you can write as a dict comp:

d3 = {key:d1.get(key, []) + d2.get(key, []) for key in  d1.viewkeys() | d2.viewkeys()}

for lists you could also chain the items:

d1 = {'a': ['x', 'y'], 'b': ['k', 'l']}
d2 = {'a': ['m', 'n'], 'c': ['p', 'r']}


from collections import defaultdict
d3 = defaultdict(list)
from itertools import chain
for key, v in chain.from_iterable((d1.items(),d2.items())):
    d3[key] += v

print(d3)

defaultdict(<type 'list'>, {'a': ['x', 'y', 'm', 'n'], 'c': ['p', 'r'], 'b': ['k', 'l']})

For python3 just use .items and .keys as they return dictview objects.

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321