How to merge two nested dict in python? - python

I have two nested dictionary data. I want to merge them to create one dictionary in python.
Dictionary data :
dict1 = {'employee':{'dev1': 'Roy'}}
dict2 = {'employee':{'dev2': 'Biswas'}}
Now I trying to create a dictionary like bellow from them.Required Output
dict_output = {'employee':{
'dev1': 'Roy',
'dev2': 'Biswas'
}
}
my try:
import json
dict1 = {'employee':{'dev1': 'Roy'}}
dict2 = {'employee':{'dev2': 'Biswas'}}
dict1.update(dict2)
print(json.dumps(dict1, indent=2))
Output:
{
"employee": {
"dev2": "Biswas"
}
}
I am unable to merge both the dictionary.Need help to merge them

This code is to support slightly different meaning of "merge". Let's say we have a nested dictionary:
dict1 = {'employee':{'devs':{'python':{'dev1':'Roy'}}}}
dict2 = {'employee':{'devs':{'cpp':{'dev1':'Biswas'}}}}
In this case the simple loop solution returns:
{'employee': {'devs': {'cpp': {'dev1': 'Biswas'}}}}
While the "intuitive" answer should be:
{'employee': {'devs': {'python': {'dev1': 'Roy'}, 'cpp': {'dev1': 'Biswas'}}}}
This is just a simple example, the real example may be much more complex.
Below is my attempt for such a nested dictionary. It works for nested data using recursion. And it also has some restrictions. For example if dict1 and dict2 have the same value which is not dictionary, dict2 has priority. On the other hand if dict1 contains dictionary and dict2 contains value with the same key, the priority is upon dict1 and dict2 is ignored. Other restrictions will require code changes.
def merge_dict(dict1, dict2):
for key, val in dict1.items():
if type(val) == dict:
if key in dict2 and type(dict2[key] == dict):
merge_dict(dict1[key], dict2[key])
else:
if key in dict2:
dict1[key] = dict2[key]
for key, val in dict2.items():
if not key in dict1:
dict1[key] = val
return dict1
dict1 = merge_dict(dict1, dict2)

You can just update the inner dictionary.
>>> dict1 = {'employee':{'dev1': 'Roy'}}
>>> dict2 = {'employee':{'dev2': 'Biswas'}}
>>>
>>> for key in dict1:
... if key in dict2:
... dict1[key].update(dict2[key])
...
>>> dict1
{'employee': {'dev2': 'Biswas', 'dev1': 'Roy'}}

Here's a solution that should work even if both dictionaries have different keys, and you want to keep them all.
from collections import defaultdict
dict1 = {'employee': {'dev1': 'Roy'}, 'aKeyNotInDict2': {}}
dict2 = {'employee': {'dev2': 'Biswas'}, 'aKeyNotInDict1': {}}
merged_dict = defaultdict(dict)
merged_dict.update(dict1)
for key, nested_dict in dict2.items():
merged_dict[key].update(nested_dict)
print(dict(merged_dict))
Output:
{
'employee': {'dev2': 'Biswas', 'dev1': 'Roy'},
'aKeyNotInDict2': {},
'aKeyNotInDict1': {}
}

#use a dict comprehension. Adding {} in get() is to set a default return value if the key doesn't exist in dict1
{k:dict(dict1.get(k,{}).items() + v.items()) for k,v in dict2.items()}
Out[689]: {'employee': {'dev1': 'Roy', 'dev2': 'Biswas'}}
#Alternatively, a less readable way to merge the dicts using the dict constructor.
{k:dict(dict1.get(k,{}), **v) for k,v in dict2.items()}
Out[690]: {'employee': {'dev1': 'Roy', 'dev2': 'Biswas'}}

Maybe you can try naapc package as follows:
>>> from naapc import NDict
>>> dict1 = NDict({'employee':{'dev1': 'Roy'}})
>>> dict2 = {'employee':{'dev2': 'Biswas'}}
>>> dict1.update(dict2)
>>> print(dict1)
{
"employee": {
"dev1": "Roy",
"dev2": "Biswas"
}
}
In case you want a normal dict:
normal_dict = deepcopy(dict1.raw_dict)
To install:
pip install naapc
doc in: https://github.com/eiphy/naapc

def m3(a,b):
if not isinstance(a,dict) and not isinstance(b,dict):return b
for k in b:
if k in a :
a[k] = m3(a[k], b[k])
else: a[k] = b[k]
return a
d1 = {1:{"a":"A"}, 2:{"b":"B"}}
d2 = {2:{"c":"C"}, 3:{"d":"D"}}
d3 = {1:{"a":{1}}, 2:{"b":{2}}}
d4 = {2:{"c":{222}}, 3:{"d":{3}}}
d5 = {'employee':{'dev1': 'Roy'}}
d6 = {'employee':{'dev2': 'Biswas'}}
print(m3(d1,d2))
print(m3(d3,d4))
print(m3(d5,d6))
"""
Output :
{1: {'a': 'A'}, 2: {'b': 'B', 'c': 'C'}, 3: {'d': 'D'}}
{1: {'a': {1}}, 2: {'b': {2}, 'c': {222}}, 3: {'d': {3}}}
{'employee': {'dev1': 'Roy', 'dev2': 'Biswas'}}
"""
Explanation:
If a and b are not dictionaries, return b
For each key in b, if the key is in a, then merge the values of the key in a and b.
If the key is not in a, then add the key and value to a.
Return a.
But yes, The best and shortest way is this:
def m4(a,b):
for k in a:
a.get(k).update(b.get(k, {}))
return a
Explanation:
The function m4 takes two dictionaries as input.
The function iterates through the first dictionary
and updates the values of the first dictionary with
the values of the second dictionary.
The function returns the first dictionary.

[key1 == key2 and dict1.get(key1).update(dict2.get(key2))
for key1, key2 in zip(dict1, dict2)]
print dict1

Related

Dictionary difference similar to set difference

I have a dictionary and a list:
dictionary = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
remove = ['b', 'c', 'e']
I need to split "dictionary" into two dictionaries using "remove". The idea is to remove keys in "remove" from "dictionary" but instead of discarding them, I want to keep them in a new dictionary. The outcome I want is
old_dictionary = {'a':1, 'd':4, 'f':6}
new_dictionary = {'b':2, 'c':3, 'e':5}
Getting "new_dictionary" is fairly easy.
new_dictionary = {}
for key, value in dictionary.items():
if key in remove:
new_dictionary[key] = value
How do I find the difference between "dictionary" and "new_dictionary" to get "old_dictionary"? I guess I could loop again only with not in remove... but is there a nice trick for dictionaries similar to set difference?
One way could be to use dict.pop in loop. dict.pop method removes the key and returns its value. So in each iteration, we remove a key in remove from dictionary and add this key along with its value to new_dict. At the end of the iteration, dictionary will have all keys in remove removed from it.
new_dict = {k: dictionary.pop(k) for k in remove}
old_dict = dictionary.copy()
Output:
>>> new_dict
{'b': 2, 'c': 3, 'e': 5}
>>> old_dict
{'a': 1, 'd': 4, 'f': 6}
Just add else
new_dictionary = {}
old_dictionary = {}
for key, value in dictionary.items():
if key in remove:
new_dictionary[key] = value
else:
old_dictionary[key] = value
Use else: to put it in the other dictionary.
new_dictionary = {}
old_dictionary = {}
for key, value in dictionary.items():
if key in remove:
new_dictionary[key] = value
else:
old_dictionary[key] = value
The dict.keys() or dict.items() can be operated like a set with other iterable sequences:
>>> dictionary = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
>>> remove = list('bce')
>>> new_dict = {key: dictionary[key] for key in remove}
>>> new_dict
{'b': 2, 'c': 3, 'e': 5}
>>> dict(dictionary.items() - new_dict.items())
{'d': 4, 'f': 6, 'a': 1}
However, in terms of performance, this method is not as good as the answer with the highest score.

How to get dictionary keys and values if both keys are in two separated dictionaries?

I would like to get a new dictionary with keys only if both dictionaries have those keys in them, and then get the values of the second one.
# example:
Dict1 = {'A':3, 'B':5, 'C':2, 'D':5}
Dict2 = {'B':3, 'C':1, 'K':5}
# result--> {'B':3, 'C':1}
As a dictionary comprehension:
>>> {k:v for k, v in Dict2.items() if k in Dict1}
{'B': 3, 'C': 1}
Or use filter:
>>> dict(filter(lambda x: x[0] in Dict1, Dict2.items()))
{'B': 3, 'C': 1}
>>>
Just another solution, doesn't use comprehension. This function loops through the keys k in Dict1 and tries to add Dict2[k] to a new dict which is returned at the end. I think the try-except approach is "pythonic".
def shared_keys(a, b):
"""
returns dict of all KVs in b which are also in a
"""
shared = {}
for k in a.keys():
try:
shared[k] = b[k]
except:
pass
return shared
Dict1 = {'A':3, 'B':5, 'C':2, 'D':5}
Dict2 = {'B':3, 'C':1, 'K':5}
print(shared_keys(Dict1, Dict2))
# >>> {'B': 3, 'C': 1}

How to return the values of dictionary key that has gained new values in a different dictionary

I have question a bit similar to:Replacing the value of a Python dictionary with the value of another dictionary that matches the other dictionaries key
However in my case I got two dictionaries
dict1 = {'foo' : ['val1' , 'val2' , 'val3'] , 'bar' : ['val4' , 'val5']}
dict2 = {'foo' : ['val2', 'val10', 'val11'] , 'bar' : ['val1' , 'val4']}
What I want to return is
dict3 = {'foo' : ['val10', 'val11'] , 'bar' : ['val1']}
and the opposite which is
dict4 = {'foo' : ['val1', 'val3'] , 'bar' : ['val5']}
where dict3 returns a dictionary of the values the keys 'foo' and 'bar' has gained in dict2 and the dict4 is a dictionary of the values the keys 'foo' and 'bar' has lost in dict2
One way I have tried solving this is to:
iterate over both dictionaries then
if key of dict1 == key of dict2
return the values of the key in dict1 and compare with the values in dict2
return the values that aren't in both
as a dictionary of the key and those values
This idea isn't working and obviously highly inefficient. I was hoping there is a more efficient working way to do this
Two dict comprehensions will do the trick:
dict3 = {k: [x for x in v if x not in dict1[k]] for k, v in dict2.items()}
print(dict3)
# {'foo': ['val10', 'val11'], 'bar': ['val1']}
dict4 = {k: [x for x in v if x not in dict2[k]] for k, v in dict1.items()}
print(dict4)
# {'foo': ['val1', 'val3'], 'bar': ['val5']}
The above two comprehensions basically filter out the values from key that don't exist in the other dictionary, which is done both ways.
You can also do this without dict comprehensions:
dict3 = {}
for k,v in dict2.items():
dict3[k] = [x for x in v if x not in dict1[k]]
print(dict3)
# {'foo': ['val10', 'val11'], 'bar': ['val1']}
dict4 = {}
for k,v in dict1.items():
dict4[k] = [x for x in v if x not in dict2[k]]
print(dict4)
# {'foo': ['val1', 'val3'], 'bar': ['val5']}

Python convert dict of lists to dict of sets?

I have:
myDict = {'a': [1,2,3], 'b':[4,5,6], 'c':[7,8,9]}
I want:
myDict = {'a': set([1,2,3]), 'b':set([4,5,6]), 'c':set([7,8,9])}
Is there a one-liner I can use to do this rather than looping through it and converting the type of the values?
You'll have to loop anyway:
{key: set(value) for key, value in yourData.items()}
If you're using Python 3.6+, you can also do this:
dict(zip(myDict.keys(), map(set, myDict.values())))
This can be done with map by mapping the values to type set
myDict = dict(map(lambda x: (x[0], set(x[1])), myDict.items()))
Or with either version of dictionary comprehension as well
myDict = {k: set(v) for k, v in myDict.items()}
myDict = {k: set(myDict[k]) for k in myDict}
You can use comprehension for it:
Basically, loop through the key-value pairs and create set out of each value for the corresponding key.
>>> myDict = {'a': [1,2,3], 'b':[4,5,6], 'c':[7,8,9]}
>>> myDict = {k: set(v) for k, v in myDict.items()}
>>> myDict
{'a': {1, 2, 3}, 'b': {4, 5, 6}, 'c': {8, 9, 7}}
You can't do it without looping anyway, but you can have the looping done in one line, with the following code:
myDict = {k:set(v) for k, v in myDict.items()}
This is basically traversing each item in your dictionary and converting the lists to sets and combining the key(str):value(set) pairs to a new dictionary and assigning it back to myDict variable.

Combining 2 dictionaries with common key

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]}
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]
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
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']}
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']}
Use dict.update() to merge two dictionaries keys: dict1['key1'].update(dict2['key1'])

Categories

Resources