Yehui He :
I would like to convert a nested list of dictionary into a substructure. And finding a robust way to do so. The structure:
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"
},
]
Into:
{
"vehicle": {
"car": {
"sedan" : {}
}
},
"fruit" : {
"apple": {},
"grape": {},
"pineapple": {}
}
}
Note that in this case it can go two level down. But It can go three deep down as well. For example one additional entry:
{
"id" : "sedan",
"name": "mini sedan"
}
My approach so far is:
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
It works in this case. The problem is it's not robust enough. I'm thinking recursion but unable to crack it. Can someone help out? Thank you
Boseong Choi :
Solution
You can use collections.defaultdict
and dict.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)
output:
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': {}}}}}
Explanation
- The idea:
dict
is mutable. working_dict
is reference table for all"id"
s.- If there is no such id, register
{}
for it. - And register elements without
id
field, as root elements intoresult_dict
.
Append
If you don't want to use collections.defaultdict
, you can only use dict.setdefault
. But it is more verbose.
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)
Guess you like
Origin http://10.200.1.11:23101/article/api/json?id=386279&siteId=1