Home > OS >  update dictionary value without overwriting
update dictionary value without overwriting

Time:10-17

I have two nested dictionary which might contain the same key but with different value (i.e. different inner-dictionary but with same key outside)

for instance:

dict_a = {"2": {"2": 0, "12": "94960", "25": "61026"}, "229": {"101": "29043", "106": "25298", "110": "48283", "112": "16219", "126": "35669", "147": "37675"}}

dict_b = {{"1": {"1": 0, "2": "84543", "3": "34854", "5": "123439}, "229": {"2": "71355", "12": "24751", "25": "33600", "229": 0}}

here the key "229" exists in both outer dictionaries, but associating with different value (different inner dictionaries)

I firstly get dict_a, and later I get dict_b. Then I want to update dict_a with all key and values added from dict_b. i.e.

dict_a_updated = {"2": {"2": 0, "12": "94960", "25": "61026"}, "229": {"101": "29043", "106": "25298", "110": "48283", "112": "16219", "126": "35669", "147": "37675", "2": "71355", "12": "24751", "25": "33600", "229": 0}}}
 {{"1": {"1": 0, "2": "84543", "3": "34854", "5": "123439}}

I haved tried .update method:

dict_a_updated = dict_a.update(dict_b)

the result is that the key "229" and its value from dict_b will overwrite the ones in dict_a. Overwriting is not wanted since I want to keep adding new values for the exisiting keys. what is the right way to do this?

CodePudding user response:

You'll have to decide how many levels of nested dict you want to merge, but it's very doable:

dict_a = {"2": {"2": 0, "12": "94960", "25": "61026"}, 
          "229": {"101": "29043", "106": "25298", "110": "48283", "112": "16219", "126": "35669", "147": "37675"}}

dict_b = {"1": {"1": 0, "2": "84543", "3": "34854", "5": "123439"}, 
          "229": {"2": "71355", "12": "24751", "25": "33600", "229": 0}}

for k, v in dict_b.items():
    if k in dict_a:
        for sub_k, sub_v in v.items():
            if sub_k in dict_a[k]: #decide what to do when there's a conflict at this level
                print("conflict: keeping value from dict_a")
            else:
                dict_a[k][sub_k] = sub_v #add missing item to dict_a[k]
    else:
        dict_a[k] = v #add missing item to dict_a

print(dict_a)

extending the problem to merge an arbitrary number of levels is a simple problem of recursion (though you have to make sure your data structure is consistent, and make decisions on how to resolve conflicts in data):

def recursive_merge(dict_a, dict_b, levels):
    for k, v in dict_b.items():
        if k in dict_a:
            if levels > 1 and isinstance(v, dict) and isinstance(dict_a[k], dict):
                recursive_merge(dict_a[k], dict_b[k], levels - 1)
            else:
                pass #keep the value from dict_a
        else:
            dict_a[k] = v
    return dict_a

print(recursive_merge(dict_a, dict_b, 2))

CodePudding user response:

You'll want to merge every nested dict from both dicts to produce a new nested merged dict of merged dicts. You can do that with a dictionary comprehension:

dict_a_updated = {k: {**dict_a.get(k, {}), **dict_b.get(k, {})}
                  for k in {*dict_a, *dict_b}}

This produces a set of all keys of the outer dict with {*dict_a, *dict_b}, and based on that a new dict with those keys (k), the value of which is a merger of the value of those keys of both dicts ({**dict_a.get(k, {}), **dict_b.get(k, {})}).

CodePudding user response:

Here is a simple python 3.9 solution to your problem:

dict_a = {'c': {1, 3, 5}, 'b': {0}}
dict_b = {'c': {2, 4, 6}, 'd': {7}}

for (key, val) in dict_b.items():
    if a_vals := dict_a.get(key):
        dict_a[key] = a_vals | val
    else:
        dict_a[key] = val

You iterate through the <key, dict> pairs in the second dictionary. If the first dictionary contains the same key you merge the two dictionaries using the new | operator introduced in python 3.9.

If the first dictionary doesn't contains the key, you add it and assign it the dictionary in the second dictionary.

After the code in the example, here is the content of dict_a:

In [1]: dict_a
Out[1]: {'c': {1, 2, 3, 4, 5, 6}, 'b': {0}, 'd': {7}}
  • Related