Разобрать ответ json, чтобы получить родительский / дочерний словарь

У меня есть список jsons (это первоначально ответ от getRases API TestRail), который я пытаюсь проанализировать. Вот пример JSON:

[
{
    "id": 1,
    "parent_id": null,
},
{
    "id": 2,
    "parent_id": 1,
},
{
    "id": 6,
    "parent_id": null,
},
{
    "id": 16,
    "parent_id": 2,
},
{
    "id": 7,
    "parent_id": 1,
},
{
    "id": 3,
    "parent_id": 6
}
]

Я хочу выяснить, какие идентификаторы попадают под исходный родительский идентификатор. например id:1 а также "id": 6, являются самыми верхними уровнями родительских узлов, так как "parent_id": null для них.

Я хочу, чтобы все дочерние узлы попадали под верхнюю часть большинства родителей. В этом примере вот отношения, основанные на parent_id

1 -> [2,7] -> 16

6 -> 3

Основная цель состоит в том, чтобы определить, каковы все дочерние (и дочерние) узлы для родительского узла верхнего уровня. Я не заинтересован в знании отношений между родителями и детьми.

что я хочу проанализировать, это получить следующий вывод:

{
 1: [2,7,16],
 6: 3
}

Один из подходов состоит в том, чтобы использовать несколько вложенных циклов for для каждого узла верхнего родительского узла, если он представлен как parent_id и идти с этим рекурсивно, но это не выглядит очень хорошим подходом.

Буду признателен за любые комментарии / предложения

1 ответ

import json

from collections import defaultdict

data = json.loads(
    '[{"id": 1, "parent_id": null}, {"id": 2, "parent_id": 1}, {"id": 6, "parent_id": null}, {"id": 16, "parent_id": 2}, {"id": 7, "parent_id": 1}, {"id": 3, "parent_id": 6}]')

parents = {d['id']: d['parent_id'] for d in data}

class RootsDict(dict):
    def __missing__(self, key):
        parent = parents[key]
        if parent is None:
            return key
        else:
            return self[parent]

roots_dict = RootsDict()
descendants = defaultdict(list)

for d in data:
    id_ = d['id']
    if d['parent_id'] is not None:
        descendants[roots_dict[id_]].append(id_)

print(descendants)  # {1: [2, 16, 7], 6: [3]}

roots_dict разработан так, чтобы roots_dict[node] вернет родителя верхнего уровня node, или же node сам, если это уже рут. __missing__ это специальный метод, который может быть переопределен для диктовок. Это называется когда key запрашивается из dict, но нет. То, что возвращает метод, будет помещено в dict с этим значением. Так например roots_dict[16] когда первый доступ будет установлен равным roots_dict[2]который в свою очередь попросит roots_dict[1]что просто 1, Остальное довольно просто.

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