How to update values in nested dictionary if keys are in a list? [duplicate]

  • A+
Category:Languages

This question already has an answer here:

Let's say i have a list of keys

key_lst = ["key1", "key2", "key3"] 

and i have a value

value = "my_value" 

and an example dict my_dict with this structure

{ "key1": {     "key2": {         "key3": "some_value"         }     }, } 

How can i dynamically assign the new value in variable value to my_dict["key1"]["key2"]["key3"] by going thru / looping over my key_lst?

I can not just say my_dict["key1"]["key2"]["key3"] = value since the keys and the number of keys is changing. I always get the keys (the path that i have to save the value at) in a list...

I'm using Python 3.7

 


Predefined dictionary structure: functools.reduce

You can define a function using functools.reduce to apply getitem repeatedly and then set a supplied value:

from functools import reduce from operator import getitem  def set_nested_item(dataDict, mapList, val):     """Set item in nested dictionary"""     reduce(getitem, mapList[:-1], dataDict)[mapList[-1]] = val     return dataDict  key_lst = ["key1", "key2", "key3"] value = "my_value" d = {"key1": {"key2": {"key3": "some_value"}}}  d = set_nested_item(d, key_lst, value)  print(d) # {'key1': {'key2': {'key3': 'my_value'}}} 

Note operator.getitem is used to access dict.__getitem__, or its more commonly used syntactic sugar dict[]. In this instance, functools.reduce calls getitem recursively on dataDict, successively using each value in mapList[:-1] as an argument. With [:-1], we intentionally leave out the last value, so we can use __setitem__ via dict[key] = value for the final key.


Arbitrary dictionary nesting: collections.defaultdict

If you wish to add items at arbitrary branches not yet been defined, you can construct a defaultdict. For this, you can first defaultify your regular dictionary input, then use set_nested_item as before:

from collections import defaultdict  def dd_rec():     return defaultdict(dd_rec)  def defaultify(d):     if not isinstance(d, dict):         return d     return defaultdict(dd_rec, {k: defaultify(v) for k, v in d.items()})  dd = defaultify(d)  key_lst = ["key1", "key2", "key5", "key6"] value = "my_value2" dd = set_nested_item(dd, key_lst, value)  print(dd)  # defaultdict(<function __main__.<lambda>>, #             {'key1': defaultdict(<function __main__.<lambda>>, #                          {'key2': defaultdict(<function __main__.<lambda>>, #                                       {'key3': 'my_value', #                                        'key5': defaultdict(<function __main__.<lambda>>, #                                                    {'key6': 'my_value2'})})})}) 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: