5

リストの値に基づいて、ネストされた辞書の辞書でキー/値をどのように変更/作成しますか?リストの最後の項目は辞書の値であり、残りの項目は辞書内のキーを参照しますか? これはリストになります:

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):
    ...
    ...
    ValueModify(..., ...)

また、アイテムがlist_address存在しない辞書のキーを参照する場合は、それらを作成する必要があります。

4

5 に答える 5

9

一発ギャグ:

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

注:ここdict.getoperator.getitem間違った例外が生成されます。

Joel Cornett's answer のような明示的な for ループは、より読みやすいかもしれません。

存在しない中間辞書を作成する場合:

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

文字列や整数など、辞書ではない既存の中間値をオーバーライドする場合:

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

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]

テスト

>>> 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}]
于 2012-08-12T02:01:29.960 に答える
3
address_list = ["key1", "key1.1", "key1.2", "value"]

def set_value(dict_nested, address_list):
    cur = dict_nested
    for path_item in address_list[:-2]:
        try:
            cur = cur[path_item]
        except KeyError:
            cur = cur[path_item] = {}
    cur[address_list[-2]] = address_list[-1]
于 2012-08-12T00:53:05.340 に答える
1

これはあなたが求めているように機能すると思います。

def ValueModify(l, d):
  if l[0] not in d:
    d[l[0]] = dict()
  if isinstance(d[l[0]], dict):
    ValueModify(l[1:], d[l[0]])
  else:
    d[l[0]] = l[1]

isinstanceこれは型チェックであり、通常はPythonで行うことではありませんが、期待どおりに値を設定します。

-- 編集 --

nested_dict元の値が完全に入力されていない場合にネストされた値を設定するために、不足しているキー チェックに追加されました。

于 2012-08-12T00:50:22.983 に答える
0

これが再帰的な解決策です。

def unravel(d, keys):
    i = keys[0]
    keys = keys[1:]
    tmpDict = d[i]
    if type(tmpDict) != type({}):
        return tmpDict
    else:
        return unravel(tmpDict, keys)
于 2012-08-12T01:02:09.640 に答える