使用列表中的项目更改嵌套字典的字典中的值? [英] Change values in dict of nested dicts using items in a list?

查看:28
本文介绍了使用列表中的项目更改嵌套字典的字典中的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您将如何根据列表的值在嵌套字典的字典中修改/创建键/值,其中列表的最后一项是字典的值,其余项目冷藏到其中的键口述?这将是列表:

list_adddress = [ "key1", "key1.2", "key1.2.1", "value" ]

这只会在解析命令行参数时出现问题.很明显,使用 dict_nested["key1"]["key1.2"]["key1.2.1"]["value"] 在脚本中修改/创建这个值非常容易.

这将是一个嵌套的字典:

dict_nested = {key1":{key1.1":{"...": "...",},key1.2":{"key1.2.1": "change_this",},},key2":{……":……"},}

我猜在这种情况下,需要使用递归函数或列表推导之类的东西.

def ValueModify(list_address, dict_nested):......值修改(..., ...)

此外,如果 list_address 中的项目会冷藏到不存在的字典中的键,则应该创建它们.

解决方案

One-liner:

keys, (newkey, newvalue) = list_address[:-2], list_address[-2:]减少(dict.__getitem__,键,dict_nested)[newkey] = newvalue

注意:dict.getoperator.getitem 会在这里产生错误的异常.

Joel Cornett 的回答中的显式 for 循环可能更具可读性.

如果你想创建不存在的中间字典:

reduce(lambda d,k: d.setdefault(k, {}), keys, dict_nested)[newkey] = newvalue

如果你想覆盖现有的不是字典的中间值,例如字符串、整数:

from collections import MutableMappingdef set_value(d, keys, newkey, newvalue, default_factory=dict):"""相当于`reduce(dict.get, keys, d)[newkey] = newvalue`如果所有`keys`都存在并且对应的值是正确的类型"""对于键中的键:尝试:val = d[键]除了 KeyError:val = d[key] = default_factory()别的:如果不是 isinstance(val, MutableMapping):val = d[key] = default_factory()d = vald[新键] = 新值

示例

list_address = ["key1", "key1.2", "key1.2.1", "key1.2.1.1", "value"]dict_nested = {key1":{key1.1":{"...": "...",},key1.2":{"key1.2.1": "change_this",},},key2":{……":……"},}set_value(dict_nested, list_address[:-2], *list_address[-2:])断言reduce(dict.get, list_address[:-1], dict_nested) == list_address[-1]

测试

<预><代码>>>>从集合导入 OrderedDict>>>d = OrderedDict()>>>set_value(d, [], 'a', 1, OrderedDict) # 不存在的键>>>d.items()[('a', 1)]>>>set_value(d, 'b', 'a', 2) # 不存在的中间键>>>d.items()[('a', 1), ('b', {'a': 2})]>>>set_value(d, 'a', 'b', 3) # 错误的中间类型>>>d.items()[('a', {'b': 3}), ('b', {'a': 2})]>>>d = {}>>>set_value(d, 'abc', 'd', 4)>>>reduce(dict.get, 'abcd', d) == d['a']['b']['c']['d'] == 4真的>>>从集合导入 defaultdict>>>autovivify = lambda: defaultdict(autovivify)>>>d = 自动激活()>>>set_value(d, 'abc', 'd', 4)>>>reduce(dict.get, 'abcd', d) == d['a']['b']['c']['d'] == 4真的>>>set_value(1, 'abc', 'd', 4) #doctest:+IGNORE_EXCEPTION_DETAIL回溯(最近一次调用最后一次):...类型错误:>>>set_value([], 'abc', 'd', 4) #doctest:+IGNORE_EXCEPTION_DETAIL回溯(最近一次调用最后一次):...类型错误:>>>L = [10]>>>set_value(L, [0], 2, 3)>>>升[{2: 3}]

How would you modify/create keys/values in a dict of nested dicts based on the values of a list, in which the last item of the list is a value for the dict, and the rest of items reefer to keys within dicts? This would be the list:

list_adddress = [ "key1", "key1.2", "key1.2.1", "value" ]

This would only be a problem in situations like when parsing command line arguments. It's obvious that modifying/creating this value within a script would be pretty easy using dict_nested["key1"]["key1.2"]["key1.2.1"]["value"].

This would be a nested dict of dicts:

dict_nested = { 
    "key1": {
                "key1.1": { 
                            "...": "...",
                },
                "key1.2": { 
                            "key1.2.1": "change_this",
                },
            },

    "key2": {
                "...": "..."
            },
}

I guess that in this case, something like a recursive function or a list comprehension would be required.

def ValueModify(list_address, dict_nested):
    ...
    ...
    ValueModify(..., ...)

Also, if items in list_address would reefer to keys in non-existing dictionaries, they should be created.

解决方案

One-liner:

keys, (newkey, newvalue) = list_address[:-2], list_address[-2:]
reduce(dict.__getitem__, keys, dict_nested)[newkey] = newvalue

Note: dict.get and operator.getitem would produce wrong exceptions here.

An explicit for-loop as in Joel Cornett's answer might be more readable.

If you want to create non-existing intermediate dictionaries:

reduce(lambda d,k: d.setdefault(k, {}), keys, dict_nested)[newkey] = newvalue

If you want to override existing intermediate values that are not dictionaries e.g., strings, integers:

from collections import MutableMapping

def set_value(d, keys, newkey, newvalue, default_factory=dict):
    """
    Equivalent to `reduce(dict.get, keys, d)[newkey] = newvalue`
    if all `keys` exists and corresponding values are of correct type
    """
    for key in keys:
        try:
            val = d[key]
        except KeyError:
            val = d[key] = default_factory()
        else:
            if not isinstance(val, MutableMapping):
                val = d[key] = default_factory()
        d = val
    d[newkey] = newvalue

Example

list_address = ["key1", "key1.2", "key1.2.1", "key1.2.1.1", "value"]
dict_nested = {
    "key1": {
                "key1.1": {
                            "...": "...",
                },
                "key1.2": {
                            "key1.2.1": "change_this",
                },
            },

    "key2": {
                "...": "..."
            },
}

set_value(dict_nested, list_address[:-2], *list_address[-2:])
assert reduce(dict.get, list_address[:-1], dict_nested) == list_address[-1]

Tests

>>> from collections import OrderedDict
>>> d = OrderedDict()
>>> set_value(d, [], 'a', 1, OrderedDict) # non-existent key
>>> d.items()
[('a', 1)]
>>> set_value(d, 'b', 'a', 2) # non-existent intermediate key
>>> d.items()
[('a', 1), ('b', {'a': 2})]
>>> set_value(d, 'a', 'b', 3) # wrong intermediate type
>>> d.items()
[('a', {'b': 3}), ('b', {'a': 2})]
>>> d = {}
>>> set_value(d, 'abc', 'd', 4)
>>> reduce(dict.get, 'abcd', d) == d['a']['b']['c']['d'] == 4
True
>>> from collections import defaultdict
>>> autovivify = lambda: defaultdict(autovivify)
>>> d = autovivify()
>>> set_value(d, 'abc', 'd', 4)
>>> reduce(dict.get, 'abcd', d) == d['a']['b']['c']['d'] == 4
True
>>> set_value(1, 'abc', 'd', 4) #doctest:+IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TypeError:
>>> set_value([], 'abc', 'd', 4) #doctest:+IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TypeError:
>>> L = [10]
>>> set_value(L, [0], 2, 3)
>>> L
[{2: 3}]

这篇关于使用列表中的项目更改嵌套字典的字典中的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆