Преобразование строки и значения с разделителями в иерархический 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, используемая здесь, является слегка измененной версией поиска по упомянутому здесь дикту

Другие вопросы по тегам