开发者

Convert a list into a nested dictionary

For example I have

x = ['a','b','c']
开发者_如何学Go

I need to convert it to:

y['a']['b']['c'] = ''

Is that possible?

For the background, I have a config file which contains dotted notation that points to a place in some json data. I'd like to use the dotted notation string to access that specific data in the json file. For example, in the config:

path_to_data = "user.name.first_name"

I'd like my script to recognize that as:

json_data["user"]["name"]["first_name"]

so I can get the value of the first_name field. I converted the original string into a list, and now I don't know how to convert it to a nested dict.

EDIT: There is an existing data structure that I need to apply the dict with. Let's say:

m = {'a': {'b': {'c': 'lolcat'}}}

so that

m['a']['b']['c']

gives me 'lolcat'. If I get the right dictionary structure (as some of the replies did), I would still need to apply this to the existing dictionary 'm'.

So, again, I get this from a config file:

c = 'a.b.c'

That I converted to a list, thinking this will make things easier:

x = ['a','b','c']

Now I have a json-like data structure:

m = {'a': {'b': {'c': 'lolcat'}}}

So the nested dict generated from 'x' should be able to traverse 'm' so that

m['a']['b']['c']

gets me the cat.


li = ['a','b','c']

d = reduce(lambda x, y: {y:x}, reversed(li+['']))

print(d)
print(d['a']['b']['c'])


I guess you also want to include a value in the end. This works for that too:

def get_value(d, l):
    if len(l) > 1:
        return get_value(d[l[0]], l[1:])
    return d[l[0]]

def add_keys(d, l, c=None):
    if len(l) > 1:
        d[l[0]] = _d = {}
        d[l[0]] = d.get(l[0], {})
        add_keys(d[l[0]], l[1:], c)
    else:
        d[l[0]] = c

def main():
    d = {}
    l1 = ['a', 'b', 'c', 'd']
    c1 = 'letters'
    l2 = [42, "42", (42,)]
    c2 = 42
    add_keys(d, l1, c1)
    print d
    add_keys(d, l2, c2)
    print d

if __name__ == '__main__':
    main()

It prints:

{'a': {'b': {'c': {'d': 'letters'}}}}
{'a': {'b': {'c': {'d': 'letters'}}}, 42: {'42': {(42,): 42}}}
letters
42

So it surely works. Recursion for the win.


>>> x = ['a','b','c']
>>> y={}
>>> y[x[-1]]=""
>>> x.pop(-1)
'c'
>>> for i in x[::-1]:
...     y={i:y}
...
>>> y
{'a': {'b': {'c': ''}}}
>>> y['a']['b']['c']
''


This will work.

#!/usr/bin/python2
from __future__ import print_function

x = ['a','b','c']

def ltod(l):
    rv = d = {}
    while l:
        i = l.pop(0)
        d[i] = {}
        d = d[i]
    return rv

d = ltod(x)
print(d)
print(d["a"]["b"]["c"])
d["a"]["b"]["c"] = "text"
print(d["a"]["b"]["c"])

Outputs:

{'a': {'b': {'c': {}}}}
{}
text


Find below sample that is not very beautiful but quite simple:

path_to_data = "user.name.first_name"
keys = path_to_data.split('.')
t = []
for key in keys[::-1]: # just to iterate in reversed order
    if not t:
        t.append({k:{}})
    else:
        t[-1] = ({k: t[-1]})
#t[0] will contain your dictionary


A general solution would be to use collections.defaultdict to create a nested dictionary. Then override __setitem__ for whatever behavior you'd like. This example will do the string parsing as well.

from collections import defaultdict

class nesteddict(defaultdict):
    def __init__(self):
        defaultdict.__init__(self, nesteddict)
    def __setitem__(self, key, value):
        keys = key.split('.')
        for key in keys[:-1]:
            self = self[key]
        defaultdict.__setitem__(self, keys[-1], value)

nd = nesteddict()
nd['a.b.c'] = 'lolcat'
assert nd['a']['b']['c'] == 'lolcat'
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜