Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 平面嵌套dict,其中新键将是所有嵌套键的元组_Python_Python 3.x - Fatal编程技术网

Python 平面嵌套dict,其中新键将是所有嵌套键的元组

Python 平面嵌套dict,其中新键将是所有嵌套键的元组,python,python-3.x,Python,Python 3.x,我有这样一句话: previous_dict = { 'dict_1': 'dict_1', 'dict_2': { 'dict_2_1': 'dict_2_1', 'dict_2_2': 'dict_2_2' }, 'dict_3': 3, 'dict_4': None, 'dict_5': dict() } 我编写了一个函数,将dict与所有键作为元组进行平放,输出为: previously_expected_

我有这样一句话:

previous_dict = {
    'dict_1': 'dict_1',
    'dict_2': {
        'dict_2_1': 'dict_2_1',
        'dict_2_2': 'dict_2_2'
    },
    'dict_3': 3,
    'dict_4': None,
    'dict_5': dict()
}
我编写了一个函数,将dict与所有键作为元组进行平放,输出为:

previously_expected_dict = {}
for key, value in previous_dict.items():
    if type(value) == dict:
        for k, v in value.items():
            previously_expected_dict[(key, k)] = v
    else:
        previously_expected_dict[(key,)] = value
输出:

print(previously_expected_dict)
{
    ('dict_1',): 'dict_1',
    ('dict_2', 'dict_2_1'): 'dict_2_1',
    ('dict_2', 'dict_2_2'): 'dict_2_2',
    ('dict_3',): 3,
    ('dict_4',): None
}
output = {
    ('dict_1', 'dict_1_1', 'dict_1_1_1'): 'dict_1_1_1',
    ('dict_1', 'dict_1_1', 'dict_1_1_2'): 'dict_1_1_2',
    ('dict_2', 'dict_2_1'): 'dict_2_1',
    ('dict_2', 'dict_2_2'): 'dict_2_2',
    ('dict_3',): 'dict_3'
}
dict_5
被丢弃,因为它没有任何值


现在需求已经改变,dict可以有任意数量的嵌套

new_dict = {
    'dict_1': {
        'dict_1_1': {
            'dict_1_1_1': 'dict_1_1_1',
            'dict_1_1_2': 'dict_1_1_2'
        }
    },
    'dict_2': {
        'dict_2_1': 'dict_2_1',
        'dict_2_2': 'dict_2_2'
    },
    'dict_3': 'dict_3',
    'dict_4': dict()
}
代码我已经试过了

def make_flat(my_dict):
    nd = dict()
    keys = []

    def loop_me(value):
        nonlocal keys
        if isinstance(value, dict):
            for k, v in value.items():
                keys.append(k)
                loop_me(v)
        else:
            nd[tuple(keys)] = value
            keys.pop(-1)

    loop_me(my_dict)
    return nd


print(make_flat(new_dict))
但我在元组中收到了额外的键

{
    ('dict_1', 'dict_1_1', 'dict_1_1_1'): 'dict_1_1_1',  # Perfect
    ('dict_1', 'dict_1_1', 'dict_1_1_2'): 'dict_1_1_2',  # Perfect
    ('dict_1', 'dict_1_1', 'dict_2', 'dict_2_1'): 'dict_2_1',  # Error, Expected is: ('dict_2', 'dict_2_1')
    ('dict_1', 'dict_1_1', 'dict_2', 'dict_2_2'): 'dict_2_2',  # Error, Expected is: ('dict_2', 'dict_2_2')
    ('dict_1', 'dict_1_1', 'dict_2', 'dict_3'): 'dict_3'  # Error, Expected is: ('dict_3',)
}
最终预期输出:

print(previously_expected_dict)
{
    ('dict_1',): 'dict_1',
    ('dict_2', 'dict_2_1'): 'dict_2_1',
    ('dict_2', 'dict_2_2'): 'dict_2_2',
    ('dict_3',): 3,
    ('dict_4',): None
}
output = {
    ('dict_1', 'dict_1_1', 'dict_1_1_1'): 'dict_1_1_1',
    ('dict_1', 'dict_1_1', 'dict_1_1_2'): 'dict_1_1_2',
    ('dict_2', 'dict_2_1'): 'dict_2_1',
    ('dict_2', 'dict_2_2'): 'dict_2_2',
    ('dict_3',): 'dict_3'
}
我尝试使用for循环和递归函数编写,失败。

您可以使用递归:

def flatten(d, c = []):
  for a, b in d.items():
    if not isinstance(b, dict):
       yield (tuple(c+[a]), b)
    else:
       yield from flatten(b, c+[a])

print(dict(flatten(previous_dict)))
输出:

{('dict_1',): 'dict_1', ('dict_2', 'dict_2_1'): 'dict_2_1', ('dict_2', 'dict_2_2'): 'dict_2_2', ('dict_3',): 3, ('dict_4',): None}
使用
新命令

{('dict_1', 'dict_1_1', 'dict_1_1_1'): 'dict_1_1_1', ('dict_1', 'dict_1_1', 'dict_1_1_2'): 'dict_1_1_2', ('dict_2', 'dict_2_1'): 'dict_2_1', ('dict_2', 'dict_2_2'): 'dict_2_2', ('dict_3',): 'dict_3'}

我使用了
deep
变量来确定和更正键,并且
make_flat
函数返回您想要的输出,但是@Ajax1234做得更清楚

def make_flat(dict_):
    new_dict = dict()
    keys = []

    def loop_recursively(value, deep=0):
        nonlocal keys
        if isinstance(value, dict):
            deep += 1
            for k, v in value.items():
                keys.append(k)
                loop_recursively(v, deep)
            else:
                deep -= 1
        else:
            keys = keys[-deep:]
            new_dict[tuple(keys)] = value
            keys.pop(-1)

    loop_recursively(dict_)
    return new_dict

您可以使用一个函数来迭代dict项,并将键前置到递归调用返回的子键元组:

def flatten(d):
    for k, v in d.items():
        if isinstance(v, dict):
            for s, i in flatten(v):
                yield (k, *s), i
        else:
            yield (k,), v
因此,
dict(展平(新dict))
返回:

{('dict_1', 'dict_1_1', 'dict_1_1_1'): 'dict_1_1_1', ('dict_1', 'dict_1_1', 'dict_1_1_2'): 'dict_1_1_2', ('dict_2', 'dict_2_1'): 'dict_2_1', ('dict_2', 'dict_2_2'): 'dict_2_2', ('dict_3',): 'dict_3'}

既然可以使用递归,为什么还要使用堆栈?@DroidX86,对不起,我不明白你的意思。太好了,你做得多么干净啊!太好了,谢谢!请注意,使用诸如
[]
之类的可变对象作为默认参数会使函数在第二次调用时行为不正常。@b仅当使用了
c.append
调用时才会出现这种情况。@Ajax1234 True。我个人会将它改为一个元组,只是为了清楚它并不意味着要被改变。它是有效的,谢谢你的努力,但是我将使用@Ajax1234而不是我的方法。