Combining 2 dictionaries with common key

10,192

Solution 1

All you need to do is to modify append to extend which will then add the elements of the list rather than adding the list itself. See the list docs for more details on the difference between append and extend.

dict1 = {'key1':['value11','value12','value13'] , 'key2':['value21','value22','value23']}
dict2 = {'key1':['value14','value15'] , 'key2':['value24','value25']}

dict3 = {}
for key in set().union(dict1, dict2):
    if key in dict1: dict3.setdefault(key, []).extend(dict1[key])
    if key in dict2: dict3.setdefault(key, []).extend(dict2[key])

print(dict3)
# {'key2': ['value21', 'value22', 'value23', 'value24', 'value25'], 'key1': ['value11', 'value12', 'value13', 'value14', 'value15']}

Alternatively you could use a collections.defaultdict with the default set to list as shown below.

from collections import defaultdict
dict3 = defaultdict(list)

for key in set().union(dict1, dict2):
  for dic in [dict1, dict2]:
    if key in dic:
      dict3[key] += dic[key]

Solution 2

Here is a generic method on which you can pass as many dict as you want as parameter.

>>> def mix_dict(*args):
       res = {}
       for d in args:
           if not isinstance(d, dict):
               continue
           for k, v in d.iteritems():
               res.setdefault(k, [])
               if isinstance(v, list):
                   res[k].extend(v)
               else:
                   res[k].append(v)
       return res
>>> dict1 = {'key1':['value11','value12','value13'] , 'key2':['value21','value22','value23']}
>>> dict2 = {'key1':['value14','value15'] , 'key2':['value24','value25']}
>>> dict3 = mix_dict(dict1, dict2)
>>> print dict3
... {'key1': ['value11', 'value12', 'value13', 'value14', 'value15'],
     'key2': ['value21', 'value22', 'value23', 'value24', 'value25']}

Solution 3

You can do it much simpler but if you want to use your code just change append to extend

dict1 = {'key1':['value11','value12','value13'] , 'key2':['value21','value22','value23']}
dict2 = {'key1':['value14','value15'] , 'key2':['value24','value25']}

dict3 = {}
for key in (dict1.viewkeys() | dict2.keys()):
    if key in dict1: dict3.setdefault(key, []).extend(dict1[key])
    if key in dict2: dict3.setdefault(key, []).extend(dict2[key])

print dict3

output:

{'key2': ['value21', 'value22', 'value23', 'value24', 'value25'], 'key1': ['value11', 'value12', 'value13', 'value14', 'value15']}

You can read this post about the difference ov append to extend

Solution 4

Here is another way to do this.

You can support merging N dicts of lists into a single dict of lists with this function:

def mergeDoLs(*dicts):
    def flatten(LoL):
        return [e for l in LoL for e in l]

    rtr={k:[] for k in set(flatten(d.keys() for d in dicts))}
    for k, v in flatten(d.items() for d in dicts):
        rtr[k].extend(v)
    return rtr

To use:

>>> dict1 = {'key1':['value11','value12','value13'] , 'key2':['value21','value22','value23'], 'key3':[1]}
>>> dict2 = {'key1':['value14','value15'] , 'key2':['value24','value25']}
>>> dict3 = {'key3':[2]}
>>> mergeDoLs(dict1, dict2, dict3) 
{'key3': [1, 2], 'key2': ['value21', 'value22', 'value23', 'value24', 'value25'], 'key1': ['value11', 'value12', 'value13', 'value14', 'value15']}
Share:
10,192
Hypothetical Ninja
Author by

Hypothetical Ninja

Surviving.

Updated on July 25, 2022

Comments

  • Hypothetical Ninja
    Hypothetical Ninja almost 2 years

    I have two dictionaries and need to combine the values of similar keys in them. Here's an example:

    dict1 = {'key1':[value11,value12,value13] , 'key2':[value21,value22,value23]}
    dict2 = {'key1':[value14,value15] , 'key2':[value24,value25]}
    

    I used :

    dict3 = {}
    for key in (dict1.viewkeys() | dict2.keys()):
        if key in dict1: dict3.setdefault(key, []).append(dict1[key])
        if key in dict2: dict3.setdefault(key, []).append(dict2[key])
    

    which gives me:

    dict3 = {'key1':[[value11,value12,value13],[value14,value15]] , 'key2':[[value21,value22,value23],[value24,value25]]}
    

    What I want is a simple one like:

    Desired output :

     dict3 = {'key1':[value11,value12,value13,value14,value15] , 'key2':[value21,value22,value23,value24,value25]}
    
    • njzk2
      njzk2 almost 10 years
      probably a simple print {k:dict1.get(k, []) + dict2.get(k, []) for k in set(dict1.keys() + dict2.keys())} would do
    • Padraic Cunningham
      Padraic Cunningham almost 10 years
      do you still want the averages?
    • Hypothetical Ninja
      Hypothetical Ninja almost 10 years
      Yes , but others told me to ask it as a separate question
    • Padraic Cunningham
      Padraic Cunningham almost 10 years
      lol and when you did you were asked to edit this question, I had an answer to the question you deleted
    • Hypothetical Ninja
      Hypothetical Ninja almost 10 years
  • Hypothetical Ninja
    Hypothetical Ninja almost 10 years
    what does defaultdict(list) do??
  • Ffisegydd
    Ffisegydd almost 10 years
    defaultdict(list) is similar to using setdefault in your example. Basically if the key isn't already in dict3 then it will set the value as default []. This way is just a bit neater (IMHO).
  • Quentin THEURET
    Quentin THEURET almost 10 years
    I dislike the except KeyError: pass − It's a bad management of Exceptions.
  • Quentin THEURET
    Quentin THEURET almost 10 years
    @Ffisegydd you can use a condition (if key in dic) instead of an Exception management with a pass statement.
  • Quentin THEURET
    Quentin THEURET almost 10 years
    Plus, I tried to test your answer and (dict1.keys() | dict2.keys()) returns an error in python 2.7
  • Ffisegydd
    Ffisegydd almost 10 years
    @QuentinTHEURET whilst I disagree with you I've modified it as it is probably more readable for people who aren't too versed in try...except... loops. And yes I changed it to keys for Python 3.4 (which is what I used).