Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: How to recursively merge 2 dictionaries? [duplicate]

Suppose we have 2 dictionaries:

a = {
    "key1": "value1",
    "key2": "value2",
    "key3": {
        "key3_1": "value3_1",
        "key3_2": "value3_2"
    }
}

b = {
    "key1": "not_key1",
    "key4": "something new",
    "key3": {
        "key3_1": "Definitely not value3_1",
        "key": "new key without index?"
    }
}

As a result of the merger, I need to get the following dictionary:

{
    "key1": "not_key1",
    "key2": "value2",
    "key3": {
        "key3_1": "Definitely not value3_1",
        "key3_2": "value3_2",
        "key": "new key without index?"
    },
    "key4": "something new"
}

I have this kind of code:

def merge_2_dicts(dict1, dict2):
    for i in dict2:
        if not type(dict2[i]) == dict:
            dict1[i] = dict2[i]
        else:
            print(dict1[i], dict2[i], sep="\n")
            dict1[i] = merge_2_dicts(dict1[i], dict2[i])
    return dict1

It works and gives me the desired result, but I'm not sure if it can be done more simply. Is there an easier/shorter option?


1 Answers

I think your code is almost good. I see only issue what if key is missing in target dictionary?

def merge_dicts(tgt, enhancer):
    for key, val in enhancer.items():
        if key not in tgt:
            tgt[key] = val
            continue

        if isinstance(val, dict):
            merge_dicts(tgt[key], val)
        else:
            tgt[key] = val
    return tgt

This code, do most of the same what you have written.

  1. check if key present in target dict, if not update regardless type.
  2. if val is dict, then we use recusion
  3. if val is not dict then update from enhancing dict

But I see still one issue what if in target dict value is string and in enhancer value is dict?

enhancer = {
    "key3": {
        "key3_1": "value3_1",
        "key3_2": "value3_2"
    }
}

tgt = {
    "key3": "string_val"
}

Then it depends what do you prefer:

  1. Overwrite string with dict from enhancer:
def merge_dicts(tgt, enhancer):
    for key, val in enhancer.items():
        if key not in tgt:
            tgt[key] = val
            continue

        if isinstance(val, dict):
            if not isinstance(tgt[key], dict):
                tgt[key] = dict()
            merge_dicts(tgt[key], val)
        else:
            tgt[key] = val
    return tgt
  1. Keep string value from target dict:
def merge_dicts(tgt, enhancer):
    for key, val in enhancer.items():
        if key not in tgt:
            tgt[key] = val
            continue

        if isinstance(val, dict):
            if not isinstance(tgt[key], dict):
                continue
            merge_dicts(tgt[key], val)
        else:
            tgt[key] = val
    return tgt
like image 173
Peter Trcka Avatar answered Oct 21 '25 23:10

Peter Trcka