Home > database >  Python recursively merge deeply nested dictionaries and create a list for values which key is overla
Python recursively merge deeply nested dictionaries and create a list for values which key is overla

Time:11-24

dict1:

{
    'level_1_a': 1,
    'level_1_b': {
        'level_2_a': 2,
        'level_2_b': {
            'level_3_a': 3
        },
        'level_2_c': {
            'level_3_b': 4
        }
    }
}

dict2:

{
    'level_1_a': 2,
    'level_1_b': {
        'level_2_a': 2,
        'level_2_b': {
            'level_3_a': 2
        },
        'level_2_c': {
            'level_3_b': 2
        }
    }
}  

Desired output:

{
    'level_1_a': [1,2]
    'level_1_b': {
        'level_2_a': 2,
        'level_2_b': {
            'level_3_a': [3,2]
        },
        'level_2_c': {
            'level_3_b': [4,2]
        }
    }
}  

I would like to recursively merge dictionaries without replacing the items of keys and create a list for values if the key existed. The desired output on level_2_a can be a single level list.

CodePudding user response:

Here is a recursive merge:

import collections.abc

def merge(a, b, path=None):
  if path is None: path = []
  for key in b:
    if key in a:
      if isinstance(a[key], collections.abc.Mapping) and isinstance(b[key], collections.abc.Mapping):
        merge(a[key], b[key], path   [str(key)])
      elif a[key] != b[key]:
        a[key]=[a[key],b[key]]
      else:
        pass
    else:
      a[key] = b[key]
  return a

With your example:

>>> merge(dict1,dict2)
>>> dict1
{"level_1_a": [1, 2], 
 "level_1_b": {
      "level_2_a": 2, 
      "level_2_b": {
           "level_3_a": [3, 2]}, 
      "level_2_c": {
           "level_3_b": [4, 2]}}}

Note: It is destructive to dict a so make a deep copy if you want the original LH dict.

Note 2: This is super limited in application. Primarily to the example given. Won't work if the values are lists or dicts, etc

  • Related