python - 从路径和值创建嵌套字典
问题描述
我需要 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'
解决方案
与链接的代码一样,预期的结果是无效的,所以我对你的意图做了一两个猜测。
首先,
{'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
}
}
}
}
稍微清理一下这段代码留给读者作为练习。
推荐阅读
- c# - 如何在 Blazor Signalr 的多个窗口中刷新同一登录用户的数据
- apache-spark - 覆盆子上的 spark-shell,4 次尝试中的 1 次尝试从另一个开始我收到各种错误消息
- java - 将spring boot war文件部署到外部tomcat
- r - 我怎样才能得到一系列数字作为我的答案,*不仅是最后一个数字
- git - 视觉工作室 + Git
- asp.net-mvc - Asp.Net Core 5.0 中带有 cookie 的电子商务用户存储桶系统
- python - 如果将参数传递给类,如何抛出自定义异常
- java - 我正在处理注册登记。我正在努力使用以下方法 RemoveMember()
- c - 使用非常规的 for 循环更高效的 Asm?
- angular - 如何创建实现行突出显示行选择的角度基表(或行)组件?