This question is about the most basic problem of deleting a key:value pair at a found key, iterating over a whole dictionary.
Deleting a key:value pair should happen much more often than the special problem of replacing the key:value pair by its value at How can I replace a key:value pair by its value whereever the chosen key occurs in a deeply nested dictionary?. Saying that these two problems are different enough may not sound so plausible at first since the wording seems almost the same, but then, please check the code solutions and test it. There is a reason why it took some hour to find it out.
The 2011 question Modifying a Python dict while iterating over it (85k views) does not even seem to have found a working answer, though it is also outdated, admittedly.
I have a dictionary that is nested many times.
{
"key0": {
"key1a": {
"sub_key2a": "sub_value2a",
"sub_key2b": "sub_value2b"
},
"key1b": {
"key_XYZ": {
"sub_key2a": "sub_value2a",
"sub_key2b": "sub_value2b"
}
}
}
}
The result should look like this, deleting all "sub_key2a"
keys with their values:
{
"key0": {
"key1a": {
"sub_key2b": "sub_value2b"
},
"key1b": {
"key_XYZ": {
"sub_key2b": "sub_value2b"
}
}
}
}
When I looped through the items of the dictionary to delete, I got the error
RuntimeError: dictionary changed size during iteration
which needs somehow to be avoided.
How can I remove the "sub_key2a": SOME_VALUE
key-value pair each time the key "sub_key2a"
occurs somewhere in the dictionary?
The trick is to find out in advance whether a target_key is among the next children (= this_dict[key]
= the values of the current dict iteration) before you reach the child level recursively. Only then you can still delete a key:value pair of the child level while iterating over a dictionary. Once you have reached the same level as the key to be deleted and then try to delete it from there, you get the error:
RuntimeError: dictionary changed size during iteration
Thus, the code looks as follows:
import copy
def find_remove(this_dict, target_key, bln_overwrite_dict=False):
if not bln_overwrite_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):
if target_key in this_dict[key]:
this_dict[key].pop(target_key)
this_dict[key] = find_remove(this_dict[key], target_key)
return this_dict
dict_nested_new = find_remove(nested_dict, "sub_key2a")
This is almost a copy of the spin-off How can I replace a key:value pair by its value wherever the chosen key occurs in a deeply nested dictionary?. But it took me a while to change that answer so that it would delete a key:value by its key. That is why I am sharing this, please mind that 95% of the credits go to the link!
The main added value over the "spun-off answer" is that you search for the target_key
in the values in advance of entering the next recursion level by checking if target_key in this_dict[key]:
.
If you want to print or save the dictionary nicely, see How do I write JSON data to a file?.