["python","dictionary"]
Access nested dictionary items via a list of keys?

I have a complex dictionary structure which I would like to access via a list of keys to address the correct item. dataDict = { "a":{ "r": 1, "s": 2, "t": 3 }, "b":{ "u": 1, "v": { "x": 1, "y": 2, "z": 3 }, "w": 3 } } maplist = ["a", "r"] or maplist = ["b", "v", "y"] I have made the following code which works but I'm sure there is a better and more efficient way to do this if anyone has an idea. # Get a given data from a dictionary with position provided as a list def getFromDict(dataDict, mapList): for k in mapList: dataDict = dataDict[k] return dataDict # Set a given data in a dictionary with position provided as a list def setInDict(dataDict, mapList, value): for k in mapList[:-1]: dataDict = dataDict[k] dataDict[mapList[-1]] = value
Use reduce() to traverse the dictionary: from functools import reduce # forward compatibility for Python 3 import operator def getFromDict(dataDict, mapList): return reduce(operator.getitem, mapList, dataDict) and reuse getFromDict to find the location to store the value for setInDict(): def setInDict(dataDict, mapList, value): getFromDict(dataDict, mapList[:-1])[mapList[-1]] = value All but the last element in mapList is needed to find the 'parent' dictionary to add the value to, then use the last element to set the value to the right key. Demo: >>> getFromDict(dataDict, ["a", "r"]) 1 >>> getFromDict(dataDict, ["b", "v", "y"]) 2 >>> setInDict(dataDict, ["b", "v", "w"], 4) >>> import pprint >>> pprint.pprint(dataDict) {'a': {'r': 1, 's': 2, 't': 3}, 'b': {'u': 1, 'v': {'w': 4, 'x': 1, 'y': 2, 'z': 3}, 'w': 3}} Note that the Python PEP8 style guide prescribes snake_case names for functions. The above works equally well for lists or a mix of dictionaries and lists, so the names should really be get_by_path() and set_by_path(): from functools import reduce # forward compatibility for Python 3 import operator def get_by_path(root, items): """Access a nested object in root by item sequence.""" return reduce(operator.getitem, items, root) def set_by_path(root, items, value): """Set a value in a nested object in root by item sequence.""" get_by_path(root, items[:-1])[items[-1]] = value And for completion's sake, a function to delete a key: def del_by_path(root, items): """Delete a key-value in a nested object in root by item sequence.""" del get_by_path(root, items[:-1])[items[-1]]