0

Other questions

This is a spin-off from How can I replace a key-value pair in a nested dictionary with the value from the same key-value pair? where the answer is working only in a one-time-nested dictionary. And it is a spin-off from Loop through all nested dictionary values? which I could not get to work on this problem.

Before:

I have a dictionary that is nested many times.

dict_nested = {
    "key_":{
        "key0a":{
            "key1a":{
                "sub_key2a":"sub_value2a",
                "sub_key2b":"sub_value2b"},
            "key1b":"value1b"},
        "key0b":{
            "key_XYZ":{
                "key1a":{
                    "sub_key2a":"sub_value2a",
                    "sub_key2b":"sub_value2b"},
                "key1b":"value1b"}
            }
        }
    }

After:

The result should look like this:

dict_nested_new = {
    "key_":{
        "key0a":{
            "sub_key2a":"sub_value2a",
            "sub_key2b":"sub_value2b",
            "key1b":"value1b"},
        "key0b":{
            "key_XYZ":{
                "sub_key2a":"sub_value2a",
                "sub_key2b":"sub_value2b",
                "key1b":"value1b"}
            }
        }
    }

Modifying a Python dict while iterating over it

When I looped through the items of the dictionary to delete / replace, I got the error

RuntimeError: dictionary changed size during iteration

which needs somehow to be avoided.

How can I replace the "key1a":SOME_VALUE key-value pair with its value each time it occurs somewhere in the dictionary?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
questionto42
  • 7,175
  • 4
  • 57
  • 90

1 Answers1

2

As I understand it, you want to recursively search for a key in a nested dict and promote its value.

This might not be super efficient, but it should work. It also does not really explore dictionaries with lists as values but your example data does not have them so I did not implement that.

import copy
import json

def find_replace(this_dict, target_key):
    ## optional depending on if you care that you mutate this_dict
    this_dict = copy.deepcopy(this_dict)

    for key in this_dict:
        # if the current value is a dict, dive into it
        if isinstance(this_dict[key], dict):
            this_dict[key] = find_replace(this_dict[key], target_key)

        # if the current key is our target merge the values and remove the key
        if key == target_key:
            this_dict = {**this_dict, **this_dict[key]}
            del this_dict[key]

    return this_dict

dict_nested = {
    "key_":{
        "key0a":{
            "key1a":{
                "sub_key2a":"sub_value2a", 
                "sub_key2b":"sub_value2b"
            }, 
            "key1b":"value1b"
        },
        "key0b":{
            "key_XYZ":{
                "key1a":{
                    "sub_key2a":"sub_value2a", 
                    "sub_key2b":"sub_value2b",
                    "key1a": {
                        "sub_key3a":"sub_value3a", 
                        "sub_key3b":"sub_value3b"
                    }, 
                }, 
                "key1b":"value1b"
            }
        }
    }
}

dict_nested_new = find_replace(dict_nested, "key1a")
print(json.dumps(dict_nested_new, indent=4))

Should give you:

{
    "key_": {
        "key0a": {
            "key1b": "value1b",
            "sub_key2a": "sub_value2a",
            "sub_key2b": "sub_value2b"
        },
        "key0b": {
            "key_XYZ": {
                "key1b": "value1b",
                "sub_key2a": "sub_value2a",
                "sub_key2b": "sub_value2b",
                "sub_key3a": "sub_value3a",
                "sub_key3b": "sub_value3b"
            }
        }
    }
}

Note that I added an addition level of nesting with a sub-nested key match just to show that scenario. Additional optimizations like support for lists and avoiding updates to unchanged keys available for a reasonable fee :-P

JonSG
  • 10,542
  • 2
  • 25
  • 36
  • At `print(json.dumps(result, indent=4))`, I got [TypeError: Object of type 'ndarray' is not JSON serializable](https://stackoverflow.com/questions/57269741/typeerror-object-of-type-ndarray-is-not-json-serializable) because I had a 'np.array([1])' as a value somewhere. With the solution of the link, the array can be printed as a list or string then. This is just a problem of the 'json.dumps', not of the 'nested_dict_new' which can save the np.array(). – questionto42 Jul 22 '21 at 09:34