Home > Mobile >  Python: Merge Multilevel dictionaries (append without replace)
Python: Merge Multilevel dictionaries (append without replace)

Time:03-01

I need to merge two dictionaries (multilevel), which are (in a very reduced form) like

 a = {'a' : {'b' : '1'}}
 b = {'a' : {'c' : '2'}}

The result should be

 x = {'a' : {'b: '1', 'c' : '2' }} 

Does Python (3.9) provide a function to merge them in the required way? Or can this be done in a failsave procedure?

The actual data has several more levels with different length.

Thanks in advance.

CodePudding user response:

Your question is too vague what you mean by "multilevel" since you don't provide an example. But for what you show, then the following will for every key, key, that is common to both dictionaries a and b, update the dictionary a[key] with the dictionary b[key]. This assumes, of course, that key values are dictionaries.

from copy import deepcopy

a = {'a': {'b': '1'}}
b = {'a': {'c': '2'}, 'f': {'d': '3'}}

x = deepcopy(a)
for key in b.keys():
    if key in x:
        x[key].update(b[key])
    else:
        x[key] = b[key]
print(x)

Prints:

{'a': {'b': '1', 'c': '2'}, 'f': {'d': '3'}}

It is the dict.update method that is key (pardon the pun) to the solution. If by multilevel you mean that the dictionary values are dictionaries whose values are also dictionaries, then you will need a recursive algorithm.

CodePudding user response:

a = {'a' : {'b' : '1'}}
b = {'a' : {'c' : '2'}}

aset = set(a)
bset = set(b)

c=dict()
#first common keys
for name in aset.intersection(bset):
    c[name]=dict(a[name], **b[name])
#keys in a but not in b
for name in aset-bset:
    c[name]=a[name]
#keys in b but not in a
for name in bset-aset:
    c[name]=b[name]
#print fully merged c
print(c)
>>> {'a': {'b': '1', 'c': '2'}}

I used sets to simplify finding common keys etc, you can check this question.

On a more complete example:

a = {'a' : {'b' : '1'},'e':{'l':'2'},'f':{'x':'10'}}
b = {'a' : {'c' : '2'},'e':{'i':'2'},'g':{'z':'12'}}

aset = set(a)
bset = set(b)

c=dict()
for name in aset.intersection(bset):
    c[name]=dict(a[name], **b[name])
for name in aset-bset:
    c[name]=a[name]
for name in bset-aset:
    c[name]=b[name]
print(c)
>>> {'a': {'b': '1', 'c': '2'}, 'e': {'l': '2', 'i': '2'}, 'f': {'x': '10'}, 'g': {'z': '12'}}
  • Related