Comparing dicts, updating NOT overwriting values

Viewed 136

I am not looking for something like this:

How do I merge two dictionaries in a single expression?

Generic way of updating python dictionary without overwriting the subdictionaries

Python: Dictionary merge by updating but not overwriting if value exists

I am looking for something like this:

input:

d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}

output:

new_dict = {'a': ['a'], 'b': ['b', 'c'], 'c': ['d']}

I have the following code which works but I am wondering if there is a more efficient method:

First, I create a list "unique_vals", where all the values that are present in both dicts are stored. From this, a new dictionary is created which stores all the values present in both dictionaries

unique_vals = []
new_dict = {}
for key in list(d1.keys())+list(d2.keys()) :
    unique_vals = []
    try:
        for val in d1[key]:
            try:
                for val1 in d2[key]:
                    if(val1 == val) and (val1 not in unique_vals):
                        unique_vals.append(val)
            except:
                continue
    except:        
        new_dict[key] = unique_vals
    new_dict[key] = unique_vals

Then, for every value in both dictionaries that are not listed in this new dictionary, these values are appended to the new dictionary.

for key in d1.keys():
      for val in d1[key]:
          if val not in new_dict[key]:
              new_dict[key].append(val)
for key in d2.keys():
    for val in d2[key]:
        if val not in new_dict[key]:
            new_dict[key].append(val)
3 Answers

Maybe with a defaultdict?

>>> d1 = {'a': 'a', 'b': 'b'} 
>>> d2 = {'b': 'c', 'c': 'd'}
>>> from collections import defaultdict                                         
>>>                                                                             
>>> merged = defaultdict(list)                                                  
>>> dicts = [d1, d2]                                                            
>>> for d in dicts: 
...:     for key, value in d.items(): 
...:         merged[key].append(value) 
...:                                                                            
>>> merged                                                                      
defaultdict(list, {'a': ['a'], 'b': ['b', 'c'], 'c': ['d']})

This works with any number of dictionaries in the dicts list.

As a function:

def merge_dicts(dicts):
    merged = defaultdict(list)

    for d in dicts:
        for key, value in d.items():
            merged[key].append(value)

    return merged

Here is a far simpler version:

d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}

new_dict = {key: [value] for key, value in d1.items()}
for key, value in d2.items():
    try:
        new_dict[key].append(value)
    except:
        new_dict[key] = [value]

Output:

{'a': ['a'], 'b': ['b', 'c'], 'c': ['d']}

EDIT: Solution below is for the original question, see other answers or duplicate for updated question.

A one line solution:

def merge_dicts(*dcts):
    return {k: [d[k] for d in dcts if k in d] for k in {k for d in dcts for k in d.keys()}}

d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}
print(merge_dicts(d1, d2))
# {'c': ['d'], 'a': ['a'], 'b': ['b', 'c']}
Related