1

I've few dictionaries as follows:

{"item1": {"item2": "300"}}
{"item1": {"item3": {"item4": "400"}}}
{"item1": {"item3": {"item6": "16"}}}
{"item1": {"item7": "aaa"}}
{"item1": {"item8": "bbb"}}
{"item1": {"item9": {"item10" : "2.2"}}}
{"item1": {"item9": {"item11" : "xxx"}}}

I want to merge these dictionaries as follows

{
  "item1": {
    "item2": "300",
    "item3": {
      "item4": "400",
      "item6": "16"
     },
    "item7": "aaa",
    "item8": "bbb",
    "item9": {
      "item10": "2.2",
      "item11": "xxx"
     }
  }
}

item1 is the first key in all dictionaries whereas the nested keys will vary. If there is same nested dictionary within a dictionary in two dictionaries the keys has to be merged (eg: item3 in dictionary 1 and 2). How can i achieve this?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
NagaLakshmi
  • 715
  • 3
  • 12
  • 24

3 Answers3

1
dico_list=[{"item1": {"item2": "300"}}, {"item1": {"item3": {"item4": "400"}}}, {"item1": {"item3": {"item6": "16"}}}, {"item1": {"item7": "aaa"}}, {"item1": {"item8": "bbb"}}, {"item1": {"item9": {"item10" : "2.2"}}}, {"item1": {"item9": {"item11" : "xxx"}}}]

def merge(merge_dico,dico_list):
    for dico in dico_list:
        for key,value in dico.items():
            if type(value)==type(dict()):
                merge_dico.setdefault(key,dict())
                merge(merge_dico[key],[value])
            else:
                merge_dico[key]=value
    return merge_dico

print(merge(dict(),dico_list))
#{'item1': {'item7': 'aaa', 'item9': {'item11': 'xxx', 'item10': '2.2'}, 'item8': 'bbb', 'item3': {'item4': '400', 'item6': '16'}, 'item2': '300'}}
user4624500
  • 286
  • 1
  • 10
0

I think this is easiest to do with a recursive helper function:

def merge_dict_into(target, d):
    for key, value in d:
        if isinstance(value, dict):
            recursive_target = target.setdefault(key, {})
            # if not isintance(recursive_target, dict): raise ValueError
            merge_dict_into(recursive_target, value)
        else:
            # if key in target: raise ValueError
            target[key] = value

def merge_dicts(dicts):
    target = {}
    for d in dicts:
        merge_dict_into(target, d)
    return target

I'm not sure how you want to handle dictionaries that have conflicts. For example, merging {"a": 0} with {"a": 1} or {"a": {"b": 2}}. The code above allows a non-dict value to overwrite a previous value, but it will fail if a dictionary tries to replace a non-dictionary. You can uncomment the error checking lines to make any conflict raise an exception, or perhaps write your own error handling logic that resolves the conflicts.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
0

Similar as the others, using a recursive function, however also checks if duplicate values exists in the tree:

from pprint import pprint

dicts = [{"item1": {"item2": "300"}},
         {"item1": {"item3": {"item4": "400"}}},
         {"item1": {"item3": {"item6": "16"}}},
         {"item1": {"item7": "aaa"}},
         {"item1": {"item8": "bbb"}},
         {"item1": {"item9": {"item10" : "2.2"}}},
         {"item1": {"item9": {"item11" : "xxx"}}},]


def walk_tree(fill_dict, mydict):
    for key, val in mydict.iteritems():
        if isinstance(val, dict):
            if key not in fill_dict.keys():
                fill_dict[key] = {}
            walk_tree(fill_dict[key], val)

        else:
            if key in fill_dict.keys():
                raise(StandardError, 'Duplicate')
            fill_dict[key] = val


dicts_total = {}

for mydict in dicts:
    walk_tree(dicts_total, mydict)


pprint(dicts_total)
crlb
  • 1,282
  • 12
  • 18