如何从Python中的任意长度的嵌套字典中获取键

时间:2014-10-16 19:04:49

标签: python-3.x recursion dictionary nested

我在python中有一个字典对象。我们称之为dict。该对象可以包含另一个字典,该字典又可以包含另一个字典等等。

     dict = { 'k': v, 'k1': v1, 'dict2':{'k3': v3, 'k4':v4} , 'dict3':{'k5':v5, dict4:{'k6':v6}}}

这只是一个例子。最外面的字典的长度可以是任何东西。我想通过以下两种方式从这样的字典对象中提取密钥:

  1. 获取唯一键列表。

    [k,k1,k2,k3,k4,k5,k6]
    
  2. 获取密钥列表及其父关联字典,如下所示:

    outer_dict_keys = [k ,dict2, dict3]
    dict2_keys = [k3,k4]
    dict3_keys = [k5, dict4]
    dict4_keys = [k6]
    
  3. 最外面的字典dict长度总是在变化,所以我不能硬编码任何东西。

    达到上述结果的最佳方法是什么?

1 个答案:

答案 0 :(得分:3)

使用迭代和尾递归的混合。引用未定义的名称,使间距统一,并从第一个结果中删除'k2'后,我想出了下面的代码。 (针对3.4编写和测试,它应该在任何3.x上运行,并且可能在2.7上运行。)要记住的一个关键事项是dicts的迭代顺序基本上是随机的,并且随每次运行而变化。这里进行的递归以深度优先而不是广度优先顺序访问子字节。对于dict0,两者都是相同的,但是如果dict4嵌套在dict2而不是dict3中,它们就不会存在。

dict0 = {'k0': 0, 'k1': 1, 'dict2':{'k3': 3, 'k4': 4},
         'dict3':{'k5': 5, 'dict4':{'k6': 6}}}

def keys(dic, klist=[]):
    subdics = []
    for key in sorted(dic):
        val = dic[key]
        if isinstance(val, dict):
            subdics.append(val)
        else:
            klist.append(key)
    for subdict in subdics:
        keys(subdict, klist)
    return klist

result = keys(dict0)
print(result, '\n', result == ['k0','k1','k3','k4','k5','k6'])

def keylines(dic, name='outer_dict', lines=[]):
    vals = []
    subdics = []
    for key in sorted(dic):
        val = dic[key]
        if isinstance(val, dict):
            subdics.append((key,val))
        else:
            vals.append(key)
    vals.extend(pair[0] for pair in subdics)
    lines.append('{}_keys = {}'.format(name, vals))
    for subdict in subdics:
        keylines(subdict[1], subdict[0], lines)
    return lines

result = keylines(dict0)
for line in result:
    print(line,)
print()
expect = [
        "outer_dict_keys = ['k0', 'k1', 'dict2', 'dict3']",
        "dict2_keys = ['k3', 'k4']",
        "dict3_keys = ['k5', 'dict4']",
        "dict4_keys = ['k6']"]
for actual, want in zip(result, expect):
    if actual != want:
        print(want)
        for i, (c1, c2) in enumerate(zip(actual, want)):
            if c1 != c2:
                print(i, c1, c2)