使用点表示法字符串“a.b.c.d.e”检查嵌套字典会自动创建缺少的级别

时间:2012-09-13 21:09:16

标签: python dictionary nested defaultdict

这个让我大吃一惊。鉴于以下字典:

    d = {"a":{"b":{"c":"winning!"}}}

我有这个字符串(来自外部来源,我不能改变这个比喻)。

    k = "a.b.c"

我需要确定字典是否有密钥'c',所以如果没有,我可以添加它。

这可以游戏地检索点符号值:

    reduce(dict.get, key.split("."), d)

但我无法弄清楚如何'减少'has_key检查或类似的东西。

我的最终问题是:给定“a.b.c.d.e”,我需要在字典中创建所有必要的元素,但如果它们已经存在则不要踩它们。如果有人知道做出这一切的真正方式,你就会成为我的英雄。

4 个答案:

答案 0 :(得分:22)

您可以使用无限的嵌套defaultdict

>>> from collections import defaultdict
>>> infinitedict = lambda: defaultdict(infinitedict)
>>> d = infinitedict()
>>> d['key1']['key2']['key3']['key4']['key5'] = 'test'
>>> d['key1']['key2']['key3']['key4']['key5']
'test'

鉴于你的虚线,这是你可以做的:

>>> import operator
>>> keys = "a.b.c".split(".")
>>> lastplace = reduce(operator.getitem, keys[:-1], d)
>>> lastplace.has_key(keys[-1])
False

您可以设置一个值:

>>> lastplace[keys[-1]] = "something"
>>> reduce(operator.getitem, keys, d)
'something'
>>> d['a']['b']['c']
'something'

答案 1 :(得分:11)

...或使用递归:

def put(d, keys, item):
    if "." in keys:
        key, rest = keys.split(".", 1)
        if key not in d:
            d[key] = {}
        put(d[key], rest, item)
    else:
        d[keys] = item

def get(d, keys):
    if "." in keys:
        key, rest = keys.split(".", 1)
        return get(d[key], rest)
    else:
        return d[keys]

答案 2 :(得分:3)

迭代方法怎么样?

def create_keys(d, keys):
    for k in keys.split("."):
        if not k in d: d[k] = {}  #if the key isn't there yet add it to d
        d = d[k]                  #go one level down and repeat

如果您需要将最后一个键值映射到除字典以外的任何内容,您可以将该值作为附加参数传递,并在循环之后设置它:

def create_keys(d, keys, value):
    keys = keys.split(".")
    for k in keys[:-1]:
        if not k in d: d[k] = {}
        d = d[k]            
    d[keys[-1]] = value

答案 3 :(得分:0)

d = {"a":{}}
k = "a.b.c".split(".")

def f(d, i):
    if i >= len(k):
        return "winning!"
    c = k[i]
    d[c] = f(d.get(c, {}), i + 1)
    return d

print f(d, 0)
"{'a': {'b': {'c': 'winning!'}}}"