简体   繁体   中英

Search and update nested dictionary based on key name

I have a nested dictionary of a variable depth for which I want to update a key with a string if the key is already present in the dictionary and if the key is not present add the key to the root of the dictionary. For example, let's say the original dictionary is:

 d= { 
 'key_1_level_1': 'item_1_level_1', 
 'key_2_level_1': {
    'key_1_level_2': 'item_1_level_2', 
    'key_2_level_2': 'item_2_level_2' }
 }

Now, I want to update key_1_level_2 with the string new_item so that the dictionary looks like this:

 d= { 
 'key_1_level_1': 'item_1_level_1', 
 'key_2_level_1': {
    'key_1_level_2': 'item_1_level_2', 
    'key_2_level_2': 'item_2_level_2'} 
 }

I can't use d.update({'key_1_level_2': 'new_item'}) because it won't work in lower levels besides the root. So doing it will end up in:

     d= { 
     'key_1_level_1': 'item_1_level_1', 
     'key_2_level_1': {
        'key_1_level_2': 'new_item', 
        'key_2_level_2': 'item_2_level_2'},
      {'key_1_level_2': 'new_item'} 
     }

However, please note that if the input key is key_2_level_1 with a string value. It must overwrite the dictionary in that level with the input string value.

On the other hand, if the input does not exist, ie key_3_level_1 = new_item , it should be added to the root, like:

 d= { 
 'key_1_level_1': 'item_1_level_1', 
 'key_2_level_1': {
    'key_1_level_2': 'item_1_level_2', 
    'key_2_level_2': 'item_2_level_2'}
 'key_3_level_1': 'new_item', 
 }

So far I tried this function. It will only receive string values . This works for already present keys, but fails to create new keys:

d= { 'key_1_level_1': 'item_1_level_1', 
     'key_2_level_1': {
        'key_1_level_2': 'item_1_level_2', 
        'key_2_level_2': 'item_2_level_2'} 
     }

input_key = "new_key"
value = "new_item"

def _update_dictionary(dictionary, input_key, value):
  if input_key in dictionary:
    dictionary.update({input_key: value})
  else:
    for k, v in dictionary.items():
      if isinstance(v, dict):
        _update_dictionary(v, input_key, value)
  return  dictionary
  
dictionary = _update_dictionary(d, input_key, value)
print(dictionary)
{'key_2_level_1': {'key_2_level_2': 'item_2_level_2', 'key_1_level_2': 'item_1_level_2'}, 
'key_1_level_1': 'item_1_level_1'}

Ideally the output for this should have been:

{'key_2_level_1': {'key_2_level_2': 'item_2_level_2', 'key_1_level_2': 'item_1_level_2'}, 
'key_1_level_1': 'item_1_level_1',
'new_key': 'new_item'}

What would be the best way to do this?

You need to make sure that we eventually add the key to the outer-most dictionary if we've never found it:

def _update_dictionary(dictionary, key, value, root=True):
    success = False
    if key in dictionary:
        dictionary[key] = value
        return True
    for k, v in dictionary.items():
        if isinstance(v, dict):
            success = _update_dictionary(v, key, value, root=False)
            if success:
                return True
    if root and not success:
        dictionary[key] = value
        return True
    return False

>>> _update_dictionary(d, input_key, value)
>>> print(d)
{'key_1_level_1': 'item_1_level_1',
 'key_2_level_1': {'key_1_level_2': 'item_1_level_2',
  'key_2_level_2': 'item_2_level_2'},
 'new_key': 'new_item'}

You will also note that I changed the interface of your function: Since it modifies the dictionary in-place, it shouldn't return it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM