Skip to content Skip to sidebar Skip to footer

Setting A Value In A Nested Python Dictionary Given A List Of Indices And Value

I'm trying to programmatically set a value in a dictionary, potentially nested, given a list of indices and a value. So for example, let's say my list of indices is: ['person', 'ad

Solution 1:

Something like this could help:

def nested_set(dic, keys, value):
    for key in keys[:-1]:
        dic = dic.setdefault(key, {})
    dic[keys[-1]] = value

And you can use it like this:

>>> d = {}
>>> nested_set(d, ['person', 'address', 'city'], 'New York')
>>> d
{'person': {'address': {'city': 'New York'}}}

Solution 2:

I took the freedom to extend the code from the answer of Bakuriu. Therefore upvotes on this are optional, as his code is in and of itself a witty solution, which I wouldn't have thought of.

def nested_set(dic, keys, value, create_missing=True):
    d = dic
    for key in keys[:-1]:
        if key in d:
            d = d[key]
        elif create_missing:
            d = d.setdefault(key, {})
        else:
            return dic
    ifkeys[-1] in d or create_missing:
        d[keys[-1]] = value
    return dic

When setting create_missing to True, you're making sure to only set already existing values:

# Trying to set a value of a nonexistent key DOES NOT create a new valueprint(nested_set({"A": {"B": 1}}, ["A", "8"], 2, False))
>>> {'A': {'B': 1}}

# Trying to set a value of an existent key DOES create a new valueprint(nested_set({"A": {"B": 1}}, ["A", "8"], 2, True))
>>> {'A': {'B': 1, '8': 2}}

# Set the value of an existing keyprint(nested_set({"A": {"B": 1}}, ["A", "B"], 2))
>>> {'A': {'B': 2}}

Solution 3:

Here's another option:

from collections import defaultdict
recursivedict = lambda: defaultdict(recursivedict)
mydict = recursivedict()

I originally got this from here: Set nested dict value and create intermediate keys.

It is quite clever and elegant if you ask me.

Solution 4:

First off, you probably want to look at setdefault.

As a function I'd write it as

def get_leaf_dict(dct, key_list):
    res=dct
    for key in key_list:
        res=res.setdefault(key, {})
    return res

This would be used as:

get_leaf_dict( dict, ['Person', 'address', 'city']) = 'New York'

This could be cleaned up with error handling and such. Also using *args rather than a single key-list argument might be nice; but the idea is that you can iterate over the keys, pulling up the appropriate dictionary at each level.

Solution 5:

Here is my simple solution: just write

terms = ['person', 'address', 'city'] 
result = nested_dict(3, str)
result[terms] = 'New York'  # as easy as it can be

You can even do:

terms = ['John', 'Tinkoff', '1094535332']  # account in Tinkoff Bank
result = nested_dict(3, float)
result[terms] += 2375.30

Now the backstage:

from collections import defaultdict


classnesteddict(defaultdict):
    def__getitem__(self, key):
        ifisinstance(key, list):
            d = self
            for i in key:
                d = defaultdict.__getitem__(d, i)
            return d
        else:
            return defaultdict.__getitem__(self, key)
    def__setitem__(self, key, value):
        ifisinstance(key, list):
            d = self[key[:-1]]
            defaultdict.__setitem__(d, key[-1], value)
        else:
            defaultdict.__setitem__(self, key, value)


defnested_dict(n, type):
    if n == 1:
        return nesteddict(type)
    else:
        return nesteddict(lambda: nested_dict(n-1, type))

Post a Comment for "Setting A Value In A Nested Python Dictionary Given A List Of Indices And Value"