首页 > 解决方案 > 从路径和值创建嵌套字典

问题描述

我需要 Python 中提出的类似请求的帮助:递归地从路径创建字典,但我的路径也有列表。我有时也有索引路径,如下所示

PATH       VALUE
/a/b/c      'Hi'
/a/b/d       1
/a/c/d       1
/b/c/d       1
/a/e[0]/f    1
/a/e[1]/g    2
/b/x/y[1]    'thank'
/b/x/y[2]    'you'
/b/j/b/c     2
/b/j/b/d     1
/a/e[2]/k[0]/s     '2D_1'
/a/e[2]/k[1]/s     '2D_2'

我正在寻找的预期输出字典如下:

{
    "a": {
        "b": {
            "c": "Hi",
            "d": 1
        },
        "c": {
            "d": 1
        },
        "e": [
            {
                "f": 1
            },
            {
                "g": 2
            },
            {
                "k": [
                    {
                        "s": "2D_1"
                    },
                    {
                        "s": "2D_2"
                    }
                ]
            }
        ]
    },
    "b": {
        "c": {
            "d": 1
        },
        "x": {
            "y": [
                null,
                "thank",
                "you"
            ]
        },
        "j": {
            "b": {
                "c": 2,
                "d": 1
            }
        }
    }
}

注意:路径可以多于 4 个部分(任意数量)。处理此问题并从路径和值创建字典的递归方式?

我尝试使用下面的示例代码,但坚持使用列表处理。

import re

def create_dict(data,path,value):
    nodes = path.split('/')
    thisdict = data
    index = -1
    for node in nodes[:-1]:
        keyislist = False
        if '[' in node :
            index = int(re.findall(r"\[\s*\+?(-?\d+)\s*\]", node)[0])
            node = node.split('[')[0]
            keyislist = True
        if (node not in thisdict):
            if keyislist:
                thisdict[node] = []
            elif isinstance(thisdict,dict):
                thisdict[node] = {}
        if isinstance(thisdict[node],dict):
            thisdict = thisdict[node]
        elif isinstance(thisdict[node],list):
            thisdict[node].insert(index,thisdict[node])
    thisdict[nodes[-1]] = value
    return data

data = {}
keys = '/a/b/c[0]/d/e/f'
value = 123456
path = keys[1:]
print(create_dict(data,path,value))

print('---------------')

keys = '/a/b/c[1]/d/e/g'
value = 'ABCDEFG'
path = keys[1:]
print(create_dict(data,path,value))

还增加了 2 个路径。路径 k[1] 的顺序可以是先 K[0] 路径。

/a/e[2]/k[1]/s     '2D_2'
/a/e[2]/k[0]/s     '2D_1'

标签: pythondictionaryrecursion

解决方案


与链接的代码一样,预期的结果是无效的,所以我对你的意图做了一两个猜测。

首先,

{'b':
    {'c': 'Hi' },
    {'d': 1 }
},

是语法错误。像这样的键不能有两个值。'b'必须是列表或字典。由于您已经努力将列表添加到规范中,我认为这应该是一个字典。

其次,{'y' : ['thank' , 'you']}这似乎是一个令人惊讶的结果

/b/x/y[1]    'thank'
/b/x/y[2]    'you'

它使用索引 1 和 2。如果您想要原始结果,请使用.append(混淆!),或修复输入中的索引(不要混淆)。

除此之外,解析新的列表要求涉及使用正则表达式挑选索引和元素,并使用索引以及键进入下一层嵌套。

import json
import re

def add_path(d, path, val):
    path = path.split("/")[1:]

    for i, e in enumerate(path):
        if re.search(r".?\[\d+\]$", e):
            e, idx = re.fullmatch(r"(.+)\[(\d+)\]", e).groups()
            idx = int(idx)

            if e not in d:
                d[e] = [None] * (idx + 1)
            elif len(d[e]) <= idx:
                d[e] += [None] * (idx - len(d[e]) + 1)

            if i == len(path) - 1:
                d[e][idx] = val 
            elif not d[e][idx]:    
                d[e][idx] = {}

            d = d[e][idx]
        else:
            if i == len(path) - 1:
                d[e] = val
            else:
                if e not in d:
                    d[e] = {}

                d = d[e]

if __name__ == "__main__":
    data = """
    /a/b/c      'Hi'
    /a/b/d       1
    /a/c/d       1
    /b/c/d       1
    /a/e[0]/f    1
    /a/e[1]/g    2
    /b/x/y[1]    'thank'
    /b/x/y[2]    'you'
    /b/j/b/c     2
    /b/j/b/d     1
    """
    d = {}

    def clean(x):   
        try:
            return int(x)
        except ValueError:
            return x.strip(" '")

    for path, val in [[clean(x) for x in re.split(r"\s{4,}", x)][1:] 
                      for x in data.split("\n") if x.strip()]:
        add_path(d, path, val)
    
    print(json.dumps(d, indent=4))

输出:

{
    "a": {
        "b": {
            "c": "Hi",
            "d": 1
        },
        "c": {
            "d": 1
        },
        "e": [
            {
                "f": 1
            },
            {
                "g": 2
            }
        ]
    },
    "b": {
        "c": {
            "d": 1
        },
        "x": {
            "y": [
                null,
                "thank",
                "you"
            ]
        },
        "j": {
            "b": {
                "c": 2,
                "d": 1
            }
        }
    }
}

稍微清理一下这段代码留给读者作为练习。


推荐阅读