Home > OS >  Generalized function to merge different number of dictionaries with different keys in nested diction
Generalized function to merge different number of dictionaries with different keys in nested diction

Time:04-16

I want to make a generalized function to merge different number of nested dictionaries with different keys in nested dictionaries in python. However, this below function works fine if we have same keys within nested dictioanries:

data = [dict1, dict2, dict3]

result = {k: {ik: [] for ik in dict1[k].keys()} for k in dict1.keys()}

for entry in data:
  for key, value in entry.items():
    for inner_key, inner_value in value.items():
        result[key][inner_key].append(inner_value)

My input dictionaries are:

dict1 = {"canada":{'america':189,'asia':175,'europe': 186},
     "norway":{'australia': 123,'africa':124,'brazil':125}}
dict2=  {"canada":{'florida':13,'asia':14,'europe': 15},
     "norway":{'california': 17,'africa':18,'brazil':19}}
dict3=  {"canada":{'africa':127,'asia':256,'europe': 16, 'brazil':15},
     "norway":{'australia': 17,'africa':18,'brazil':19}}
# Expected Output
{'canada': {'africa': 127,
'america': 189,
'asia': [175, 14, 256],
'brazil': 15,
'europe': [186, 15, 16],
'florida': 13},
'norway': {'africa': [124, 18, 18],
'australia': 123,
'brazil': [125, 19, 19],
'california': 17}}

CodePudding user response:

One option is to use dict.setdefault for updating the inner dictionary.

out = {}
for k in dict1.keys() | dict2.keys() | dict3.keys():
    inner = {}
    for d in [dict1, dict2, dict3]:
        for i,j in d.get(k, {}).items():
            inner.setdefault(i, []).append(j)
    out[k] = inner

If the other keys are the same across the dictionaries, we could simplify it a bit.

Also if you insist on having ints (instead of lists) for singleton lists, you could try the following (but I don't think it's a good idea to mix data types since afterwards you'll need to check if the value is int or list):

def merge_dicts(dicts):
    out = {}
    for k in dicts[0]:
        inner = {}
        for d in dicts:
            for i,j in d.get(k, {}).items():
                if i in inner and isinstance(inner[i], list):
                    inner[i].append(j)
                elif i in inner:
                    inner[i] = [inner[i], j]
                else:
                    inner[i] = j
        out[k] = inner
    return out

Output:

>>> out = merge_dicts([dict1,dict2,dict3])
{'canada': {'america': 189,
  'asia': [175, 14, 256],
  'europe': [186, 15, 16],
  'florida': 13,
  'africa': 127,
  'brazil': 15},
 'norway': {'australia': [123, 17],
  'africa': [124, 18, 18],
  'brazil': [125, 19, 19],
  'california': 17}}
  • Related