如果键在列表中,如何更新嵌套字典中的值?

时间:2019-01-10 22:45:34

标签: python python-3.x dictionary nested

假设我有一个钥匙清单

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

我有一个价值

value = "my_value"

以及具有这种结构的示例dict my_dict

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

如何通过遍历/遍历value来动态地将变量my_dict["key1"]["key2"]["key3"]中的新值分配给key_lst

我不能只说my_dict["key1"]["key2"]["key3"] = value,因为键和键的数量正在变化。我总是在列表中获取键(我必须在其中保存值的路径)...

我正在使用Python 3.7

5 个答案:

答案 0 :(得分:6)

预定义的字典结构:functools.reduce

您可以使用functools.reduce定义一个函数来重复应用getitem,然后设置一个提供的值:

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

注释operator.getitem用于访问dict.__getitem__或其更常用的语法糖dict[]。在这种情况下,functools.reducegetitem上递归调用dataDict,并依次使用mapList[:-1]中的每个值作为参数。对于[:-1],我们有意遗漏了最后一个值,因此我们可以通过__setitem__使用dict[key] = value作为最终键。


任意字典嵌套:collections.defaultdict

如果希望在尚未定义的任意分支处添加项目,则可以构造defaultdict。为此,您可以先defaultify常规字典输入,然后像以前一样使用set_nested_item

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

答案 1 :(得分:5)

您可以循环使用setdefault来迭代构建/访问级别:

d = {}
d2 = d
for k in key_lst[:-1]:
    d2 = d2.setdefault(k, {})

d2[key_lst[-1]] = value
print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}

d是对字典的引用,而d2是即弃引用,可在每次迭代时访问内部级别。

答案 2 :(得分:0)

我想您可以像这样遍历您的按键:

d = {}
a = d
for i in key_lst: 
    a[i] = {}
    if i == key_lst[-1]:
        a[i] = value
    else:
        a = a[i]
print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}

编辑:我想我误解了问题,好像字典还不存在一样回答。 jpp answer非常简洁,否则我猜!

答案 3 :(得分:0)

这就是您想要的:

def update(d, key_lst , val):
    for k in key_lst[:-1]:
        if k not in d:
            d[k] = {}
        d = d[k]
    d[key_lst[-1]] = val

d = {}

update(d, list('qwer'), 0)
# d = {'q': {'w': {'e': {'r': 0}}}}

您也可以使用defaultdict,从某种意义上讲它很整洁,但是打印起来却很丑陋……:

from collections import defaultdict

nest = lambda: defaultdict(nest)
d = nest()

def update(d, key_lst , val):
    for k in key_lst[:-1]:
        d = d[k]
    d[key_lst[-1]] = val

update(d, 'qwer', 0)

答案 4 :(得分:0)

key_lst = ["key1", "key2", "key3"]
my_dict={
"key1": {
    "key2": {
        "key3": "some_value"
        }
    },
}

val=my_dict
#loop gets second to last key in chain(path) and assigns it to val
for x in key_lst[:-1]:
    val=val[x]
#now we can update value of last key, cause dictionary key is passed by reference
val[key_lst[-1]]="new value"

print (my_dict)

#{'key1': {'key2': {'key3': 'new value'}}}