Преобразование строки и значения с разделителями в иерархический JSON с Python
У меня есть данные в следующем формате:
[['Director', 9010],
['Director - Product Manager', 9894],
['Director - Product Manager - Project Manager', 9080],
['Director - Product Manager - Project Manager - Staff', 5090],
['Director - Product Manager - Project Manager - Staff 2', 5087],
['Director - Product Manager - Project Manager 2', 9099],...]
и хотите вывод, который будет выглядеть примерно так:
{
'title': 'Director',
'id': 9010,
'children': [
{
'title': 'Product Manager',
'id': 9894,
'children': [
{
'title': 'Project Manager',
'id': 9080,
'children': [
...
]
},{
'title': 'Project Manager 2',
'id': 9099,
'children': [
...
]
}],
...
]
},
...
]
}
Я играл со словарями, но изо всех сил пытался сопоставить идентификаторы с названиями. Любые предложения приветствуются.
2 ответа
Эффективный способ сделать это - сделать внешний слой списком, а не диктом. Когда мы перебираем каждый заголовок в строке заголовков, мы ищем в текущем списке диктовку с этим заголовком. Если заголовок не существует в текущем списке, то нам нужно создать новый dict. Если он существует, то мы создаем список потомков, который определяет новый текущий список, и переходим к поиску следующего заголовка.
Я также написал рекурсивный prune
функция, которая удаляет все пустые дочерние списки, когда мы закончим вводить все данные, если вы захотите это сделать.
import json
lst = [
['Director', 9010],
['Director - Product Manager', 9894],
['Director - Product Manager - Project Manager', 9080],
['Director - Product Manager - Project Manager - Staff', 5090],
['Director - Product Manager - Project Manager - Staff 2', 5087],
['Director - Product Manager - Project Manager 2', 9099],
]
# Search for a matching name in the current list.
# If it doesn't exist, create it.
def insert(lst, name, idnum):
for d in lst:
if d['title'] == name:
break
else:
d = {'title': name, 'id': idnum, 'children': []}
lst.append(d)
return d['children']
# Remove empty child lists
def prune(lst):
for d in lst:
if d['children']:
prune(d['children'])
else:
del d['children']
# Insert the data into the master list
master = []
for names, idnum in lst:
lst = master
for name in [s.strip() for s in names.split(' - ')]:
lst = insert(lst, name, idnum)
prune(master)
# Get the top level dict from the master list
data = master[0]
print(json.dumps(data, indent=4))
выход
{
"title": "Director",
"id": 9010,
"children": [
{
"title": "Product Manager",
"id": 9894,
"children": [
{
"title": "Project Manager",
"id": 9080,
"children": [
{
"title": "Staff",
"id": 5090
},
{
"title": "Staff 2",
"id": 5087
}
]
},
{
"title": "Project Manager 2",
"id": 9099
}
]
}
]
}
С d
в качестве входных данных, переберите свой входной список с помощью.
Поскольку в каждом подсписке есть два элемента, сохраните позицию и идентификатор в переменной итерации как p
а также id
Пример, вы обрабатываете список ['Director - Product Manager - Project Manager - Staff', 5090],
Чтобы получить название каждой позиции, вы можете разделить вашу позицию, разделенную на -
и лишить ведущих и конечных пробелов. Например.,
>>> d[3][0]
'Director - Product Manager - Project Manager - Staff'
>>> map(str.strip,d[3][0].split('-'))
['Director', 'Product Manager', 'Project Manager', 'Staff']
Выходной DICT, наряду с непосредственно предыдущей позицией Staff
передается в метод рекурсивного поиска, и он выбирает все совпадения найденного значения, т.е. Project Manager
и возвращает список. Получить последний матч.
>>> recursive_search([data,],'Product Manager')[-1]
{'children': [{'children': [{'id': 5090, 'title': 'Staff'}, {'id': 5087, 'title': 'Staff 2'}], 'id': 9080, 'title': 'Project Manager'}, {'id': 9099, 'title': 'Project Manager 2'}], 'id': 9894, 'title': 'Product Manager'}
Вам нужно добавить новый идентификатор в children
ключ вышеуказанного результата!
Объединяя все вышеперечисленное,
d=[['Director', 9010],['Director - Product Manager', 9894],['Director - Product Manager - Project Manager', 9080],['Director - Product Manager - Project Manager - Staff', 5090],['Director - Product Manager - Project Manager - Staff 2', 5087],['Director - Product Manager - Project Manager 2', 9099],]
from pprint import pprint
def recursive_search(items, key):
found = []
for item in items:
if isinstance(item, list):
found += recursive_search(item, key)
elif isinstance(item, dict):
if key in item.values():
found.append(item)
found += recursive_search(item.values(), key)
return found
data={}
for p,id in d:
desig = map(str.strip,p.split('-'))
if len(desig)>1:
res = recursive_search([data,],desig[-2])[-1]
if res:
res['children']=res.get('children',[])
res['children'].append({'id':id,'title':desig[-1]})
else:
data = {'id':id,'title':p}
pprint.pprint(data)
Выход:
{'children': [{'children': [{'children': [{'id': 5090, 'title': 'Staff'},
{'id': 5087,
'title': 'Staff 2'}],
'id': 9080,
'title': 'Project Manager'},
{'id': 9099, 'title': 'Project Manager 2'}],
'id': 9894,
'title': 'Product Manager'}],
'id': 9010,
'title': 'Director'}
Ссылка: функция recursive_search, используемая здесь, является слегка измененной версией поиска по упомянутому здесь дикту