如何按键中的字符串递归分组字典

问题描述 投票:1回答:2

我有一本看起来像这样的字典:

d = {
'simulation__config__name': '0',
'simulation__config__ver': '1',
'simulation__config__rev': '2',
'simulation__model__name': '3',
'simulation__name': '4',
'site__name': '5',
'site__placement': '6',
'name': '7'}

我想按'__'拆分键并将其分组,然后按'__'拆分这些键并对其进行分组,依此类推,直到无法再进行分组为止。

最后,我会得到这样的结果:

out = {
 'simulation': {'simulation__config': {'simulation__config_name': 0,
                                       'simulation__config_ver': 1,
                                       'simulation__config_rev': 2},
                'simulation__model': {'simulation__model_name': 3},
                'simulation__name': 4},
 'site': {'site__name': 5, 'site__placement': 6},
 'name': 7}

我真的很努力尝试将递归函数放在一起。我认为我已经或多或少地想出了它,从某种意义上说,如果我手动执行它会起作用...但是我不知道如何在没有人工干预的情况下正确调用它。

这是我当前的代码:

from itertools import groupby

d = {
'simulation__config__name': '0',
'simulation__config__ver': '1',
'simulation__config__rev': '2',
'simulation__model__name': '3',
'simulation__name': '4',
'site__name': '5',
'site__placement': '6',
'name': '7'}

def get_key(string, i):
    return '__'.join(string.split('__')[0:i+1])

def recursive_group(iterable, i):
    if not isinstance(iterable, dict):
        return
    out = {}
    for k,g in groupby(iterable.keys(), lambda x: get_key(x,i)):
        inner = {key:iterable[key] for key in g}
        if k in iterable.keys():
            out.update(inner)
        else:
            out.update({k:inner})
    return out

out = recursive_group(d, 0)
#{'simulation': {'simulation__config__name': '0', 'simulation__config__ver': '1', 'simulation__config__rev': '2', 'simulation__model__name': '3', 'simulation__name': '4'}, 'site': {'site__name': '5', 'site__placement': '6'}, 'name': '7'}

out1 = recursive_group(out['simulation'], 1)
#{'simulation__config': {'simulation__config__name': '0', 'simulation__config__ver': '1', 'simulation__config__rev': '2'}, 'simulation__model': {'simulation__model__name': '3'}, 'simulation__name': '4'}

out2 = recursive_group(out1['simulation__config'], 2)
#{'simulation__config__name': '0', 'simulation__config__ver': '1', 'simulation__config__rev': '2'}

out3 = recursive_group(out2['simulation__config__name'], 3)
#None

out4 = recursive_group(out['site'], 1)
#{'site__name': '5', 'site__placement': '6'}

out5 = recursive_group(out4['site__name'], 2)
#None

out6 = recursive_group(out['name'], 1)
#None

向下分组的每个级别,我似乎都得到了预期的结果。当达到无法再进行分组的最终级别时,它将返回None。我觉得我只是缺少将它们拼凑在一起的最后几个步骤。

请帮助编码专家!

python recursion group-by itertools
2个回答
2
投票

如果您首先测试目标字典中是否已存在密钥,则不需要groupby。如果不是,则创建,否则,添加。

以下代码

import pprint

d = {
'simulation__config__name': '0',
'simulation__config__ver': '1',
'simulation__config__rev': '2',
'simulation__model__name': '3',
'simulation__name': '4',
'site__name': '5',
'site__placement': '6',
'name': '7'}

def recursive_group (iterable):
    out = {}
    for key in iterable:
        if '__' in key:
            left,right = key.split('__',1)
            if left not in out:
                out[left] = {}
            out[left][right] = iterable[key]
            if '__' in right:
                out[left] = recursive_group(out[left])
        else:
            out[key] = iterable[key]

    return out


out = recursive_group (d)
pprint.pprint (out, sort_dicts=False)

生成整洁,紧凑的嵌套字典:

{'simulation': {'config': {'name': '0', 'ver': '1', 'rev': '2'},
                'model': {'name': '3'},
                'name': '4'},
 'site': {'name': '5', 'placement': '6'},
 'name': '7'}

您可以使用另一个递归函数使用原始的完整字符串符号检索此结果中的值:

def get_value (iterable, full_name):
    if '__' in full_name:
        left,right = full_name.split('__',1)
        return get_value(iterable[left], right)
    return iterable[full_name]

print (get_value (out, 'simulation__config__ver'))

0
投票

我将答案发布在这里,因为我实际上离答案只有一步之遥。谢谢@ usr2564301的回答,它也可以使用,但是给出的结果略有不同,可以对其进行编辑以使我得到我的回答,但是无论如何...

def get_key(string, i):
    return '__'.join(string.split('__')[0:i+1])
def recursive_group(iterable, i):
    if not isinstance(iterable, dict):
        return
    out = {}
    for k,g in groupby(iterable.keys(), lambda x: get_key(x,i)):
        inner = {key:iterable[key] for key in g}
        if k in iterable.keys():
            out.update(inner)
        else:
            i += 1
            out.update({k:recursive_group(inner, i)})
    return out

我只需要确保在最后一步中递归地调用该函数:

out.update({k:recursive_group(inner, i)})

© www.soinside.com 2019 - 2024. All rights reserved.