在Python中转换字典的嵌套列表



我想将字典的嵌套列表转换为子结构。并找到一种稳健的方法来做到这一点

nested_list = [
{
"id" : "fruit",
"name" : "apple"
},
{
"name": "fruit"
},
{
"id" : "fruit",
"name" : "grape"
},
{
"id" : "fruit",
"name" : "pineapple"
},
{
"name": "vehicle"
},
{
"id" : "vehicle",
"name": "car"
},
{
"id" : "car",
"name": "sedan"
},
] 

进入:

{
"vehicle": {
"car": {
"sedan" : {}
}
},
"fruit" : {
"apple": {},
"grape": {},
"pineapple": {}
}
}

注意,在这种情况下,它可以下降两级。但它也可以深入三层。例如,一个附加条目:

{ 
"id" : "sedan", 
"name": "mini sedan" 
}

到目前为止,我的方法是:

for category in nested_list:
if 'id' not in category:
d[category['name']] = {}
for category in nested_list:
if 'id' in category and category['id'] in d:
d[category['id']][category['name']] = {}
elif 'id' in category and category['id'] not in d:
for k, v in d.items():
if category['id'] in v:
d[k][category['id']] = {category['name']: {}}
# If there are not top level key then do nothing
else:
pass

在这种情况下是有效的。问题是它不够健壮。我在想递归,但无法破解。有人能帮忙吗?谢谢

解决方案

您可以使用collections.defaultdictdict.setdefault:

from collections import defaultdict
nested_list = [
{
"id": "fruit",
"name": "apple"
},
{
"name": "fruit"
},
{
"id": "fruit",
"name": "grape"
},
{
"id": "fruit",
"name": "pineapple"
},
{
"name": "vehicle"
},
{
"id": "vehicle",
"name": "car"
},
{
"id": "car",
"name": "sedan"
},
{
"id": "sedan",
"name": "mini sedan"
},
]
working_dict = defaultdict(dict)
result_dict = {}
for item in nested_list:
name = item['name']
if 'id' in item:
id_ = item['id']
working_dict[id_].setdefault(name, working_dict[name])
else:
result_dict[name] = working_dict[name]
print(working_dict)
print(result_dict)

输出:

defaultdict(<class 'dict'>, {'fruit': {'apple': {}, 'grape': {}, 'pineapple': {}}, 'apple': {}, 'grape': {}, 'pineapple': {}, 'vehicle': {'car': {'sedan': {'mini sedan': {}}}}, 'car': {'sedan': {'mini sedan': {}}}, 'sedan': {'mini sedan': {}}, 'mini sedan': {}})
{'fruit': {'apple': {}, 'grape': {}, 'pineapple': {}}, 'vehicle': {'car': {'sedan': {'mini sedan': {}}}}}

说明

  • 这个想法:dict是可变的
  • working_dict是所有"id"的参考表
  • 如果没有这样的id,则为其注册{}
  • 并将没有id字段的元素作为根元素注册到result_dict

附加

如果不想使用collections.defaultdict,则只能使用dict.setdefault。但它更为冗长。

working_dict = {}
result_dict = {}
for item in nested_list:
name = item['name']
if 'id' in item:
id_ = item['id']
working_dict.setdefault(id_, {}).setdefault(name, working_dict.setdefault(name, {}))
else:
result_dict[name] = working_dict.setdefault(name, {})
print(result_dict)

您也可以使用递归函数手动执行此操作。想法:

  • 在输入列表中的元素上迭代
  • 忽略没有id键的元素
  • 对于键中具有id的元素:
    • 在out中递归搜索此键
    • 添加元素(如果元素已经存在,则在递归函数中添加该元素,否则在后面添加(
# Recursive search
def iterdictAdd(d, id, name):
# For all element in the dict
for k, v in d.items():
# If key match -> add
if k == id:
d[id] = {**d[id], **{name: {}}}
return True
else:
# Recursive call
if isinstance(v, dict):
if iterdictAdd(v, id, name):
return True
return False

out = {}
# Iterate all dict
for dict_ in nested_list:
# Ignore elements without "id" 
if "id" in dict_:
# Search and add this key
if not iterdictAdd(out, dict_["id"], dict_["name"]):
out[dict_["id"]] = {dict_["name"]: {}}
print(out)
# {'fruit': {
#     'apple': {},
#     'grape': {},
#     'pineapple': {}
# },
#  'vehicle': {
#     'car': {
#         'sedan': {}
#         }
#     }
# }

相关内容

  • 没有找到相关文章

最新更新