41

インデックスと値のリストを指定して、ネストされている可能性のある辞書に値をプログラムで設定しようとしています。

たとえば、私のインデックスのリストが次のようになっているとします。

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

値は

'New York'

結果として、次のような辞書オブジェクトが必要です。

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

基本的に、リストはネストされた辞書への「パス」を表します。

辞書自体は作れると思いますが、つまずくのは値の設定方法です。明らかに、これのコードを手動で書いているだけの場合は、次のようになります。

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

しかし、インデックスと値のリストがある場合、辞書にインデックスを付けて、プログラムでそのような値を設定するにはどうすればよいですか?

Python

4

8 に答える 8

68

このようなものが役立つ可能性があります:

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'}}}
于 2012-12-03T17:00:42.050 に答える
5

私はバクリウの答えからコードを拡張する自由を取りました。したがって、彼のコードはそれ自体が機知に富んだ解決策であり、私が考えもしなかったので、これに対する賛成票は任意です。

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

Trueに設定create_missingする場合は、既存の値のみを設定するようにしてください。

# 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}}
于 2018-03-15T02:45:40.287 に答える
3

まず、setdefaultを確認することをお勧めします。

関数として私はそれを次のように書きます

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

これは次のように使用されます。

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

これは、エラー処理などでクリーンアップできます。また*args、単一のキーリスト引数ではなく使用することもできます。ただし、各レベルで適切な辞書を取得して、キーを反復処理できるという考え方です。

于 2012-12-03T17:00:33.003 に答える
2

別のオプションは次のとおりです。

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

私はもともとここからこれを取得しました:ネストされたdict値を設定し、中間キーを作成します

私に言わせれば、それはかなり賢くてエレガントです。

于 2014-07-11T01:13:59.560 に答える
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))
于 2016-11-01T12:38:37.093 に答える
2

Python3のdotty_dictライブラリはこれを行うことができます。より明確にするために、ドキュメント、DottyDictを参照してください。

from dotty_dict import dotty

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

print(dot)

出力:

{'person': {'address': {'city': 'New York'}}}
于 2020-01-24T15:50:12.820 に答える
1

これらの方法のペアを使用します

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]
于 2018-12-03T01:19:32.040 に答える
1

これは、別の関数に依存しないバクリウの答えの変形です。

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'}}}
于 2019-05-30T20:56:29.940 に答える