Setting a value in a nested python dictionary given a list of indices and value

后端 未结 8 817
忘了有多久
忘了有多久 2020-12-01 09:36

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 i

相关标签:
8条回答
  • 2020-12-01 09:38

    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'}}}
    
    0 讨论(0)
  • 2020-12-01 09:38

    First off, you probably want to look at setdefault

    As a function I'd write it as

    def get_leaf_dict( dict, key_list):
        res=dict
        for key in key_list:
            res=dict.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.

    0 讨论(0)
  • 2020-12-01 09:38

    Here's a variant of Bakuriu's answer that doesn't rely on a separate function:

    keys = ['Person', 'address', 'city']
    value = 'New York'
    
    nested_dict = {}
    
    # Build nested dictionary up until 2nd to last key
    # (Effectively nested_dict['Person']['address'] = {})
    sub_dict = nested_dict
    for key_ind, key in enumerate(keys[:-1]):
        if not key_ind:
            # Point to newly added piece of dictionary
            sub_dict = nested_dict.setdefault(key, {})
        else:
            # Point to newly added piece of sub-dictionary
            # that is also added to original dictionary
            sub_dict = sub_dict.setdefault(key, {})
    # Add value to last key of nested structure of keys 
    # (Effectively nested_dict['Person']['address']['city'] = value)
    sub_dict[keys[-1]] = value
    
    print(nested_dict)
    
    >>> {'Person': {'address': {'city': 'New York'}}}
    
    0 讨论(0)
  • 2020-12-01 09:44

    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
    
    
    class nesteddict(defaultdict):
        def __getitem__(self, key):
            if isinstance(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):
            if isinstance(key, list):
                d = self[key[:-1]]
                defaultdict.__setitem__(d, key[-1], value)
            else:
                defaultdict.__setitem__(self, key, value)
    
    
    def nested_dict(n, type):
        if n == 1:
            return nesteddict(type)
        else:
            return nesteddict(lambda: nested_dict(n-1, type))
    
    0 讨论(0)
  • 2020-12-01 09:52

    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
        if keys[-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 value
    print(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 value
    print(nested_set({"A": {"B": 1}}, ["A", "8"], 2, True))
    >>> {'A': {'B': 1, '8': 2}}
    
    # Set the value of an existing key
    print(nested_set({"A": {"B": 1}}, ["A", "B"], 2))
    >>> {'A': {'B': 2}}
    
    0 讨论(0)
  • 2020-12-01 09:56

    Here's another option:

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

    I originally got this from here: https://stackoverflow.com/a/10218517/1530754.

    Quite clever and elegant if you ask me.

    0 讨论(0)
提交回复
热议问题