在给定索引和值列表的情况下,在嵌套的python字典中设置值

时间:2012-12-03 16:50:34

标签: python list dictionary

很抱歉,如果之前已经回答过这个问题 - 我一直在寻找解决方案,但我可能没有使用正确的搜索字词。

无论如何,我要做的是在给定索引列表和值的情况下,以编程方式在字典中设置一个值,可能是嵌套的。

例如,假设我的索引列表是:

['person', 'address', 'city'] 

,值为

'New York'

我想要一个字典对象,如:

{ 'Person': { 'address': { 'city': 'New York' } }

基本上,列表表示嵌套字典的“路径”。

我想我可以构建字典本身,但我磕磕绊绊的是如何设置值。显然,如果我只是手动编写代码,那将是:

dict['Person']['address']['city'] = 'New York'

但是,如果我只有一个索引列表和值,如何编入字典并以编程方式设置值?

希望这是有道理的,并不是一个愚蠢的问题... :)谢谢你的帮助。

8 个答案:

答案 0 :(得分:42)

这样的事情可能有所帮助:

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

你可以像这样使用它:

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

答案 1 :(得分:4)

首先,你可能想看看setdefault

作为一个函数,我把它写成

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

这将用作:

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

这可以通过错误处理来清理,例如,使用*args而不是单个键列表参数可能会很好;但这个想法是这样的 你可以遍历键,在每个级别上拉相应的字典。

答案 2 :(得分:2)

这是另一种选择:

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

我原来是从这里得到的:https://stackoverflow.com/a/10218517/1530754

如果你问我,那就相当聪明和优雅。

答案 3 :(得分:2)

这是我的简单解决方案:只需编写

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

你甚至可以这样做:

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

现在是后台:

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))

答案 4 :(得分:2)

我可以自由地从Bakuriu的答案中扩展代码。因此,对此的赞成是可选的,因为他的代码本身就是一个诙谐的解决方案,我不会想到。

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

create_missing设置为True时,您确保仅设置现有值:

# 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}}

答案 5 :(得分:0)

使用这两种方法

def gattr(d, *attrs):
    """
    This method receives a dict and list of attributes to return the innermost value of the give dict
    """
    try:
        for at in attrs:
            d = d[at]
        return d
    except:
        return None


def sattr(d, *attrs):
    """
    Adds "val" to dict in the hierarchy mentioned via *attrs
    For ex:
    sattr(animals, "cat", "leg","fingers", 4) is equivalent to animals["cat"]["leg"]["fingers"]=4
    This method creates necessary objects until it reaches the final depth
    This behaviour is also known as autovivification and plenty of implementation are around
    This implementation addresses the corner case of replacing existing primitives
    https://gist.github.com/hrldcpr/2012250#gistcomment-1779319
    """
    for attr in attrs[:-2]:
        # If such key is not found or the value is primitive supply an empty dict
        if d.get(attr) is None or isinstance(d.get(attr), dict):
            d[attr] = {}
        d = d[attr]
    d[attrs[-2]] = attrs[-1]

答案 6 :(得分:0)

这是Bakuriu答案的一种变体,它不依赖于单独的功能:

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'}}}

答案 7 :(得分:0)

Pyhton3提供了dotty_dict lib。有关更多说明,请参见文档https://dotty-dict.readthedocs.io/en/latest/

from dotty_dict import dotty

dot = dotty()
string = '.'.join(['person', 'address', 'city']) 
dot[string] = 'New York'

print(dot)

输出:

{'person': {'address': {'city': 'New York'}}}