У меня есть словарь с таким корпусом:
[
{
"children": [
{
"children": [
{
"children": [
{
"label": "Something20",
"id": 11
},
{
"label": "Something19",
"id": 12
}
],
"label": "Something18",
"id": 5
},
{
"children": [
{
"label": "Something15",
"id": 13
}
],
"label": "Something14",
"id": 6
}
],
"label": "Something2",
"id": 2
},
{
"children": [
{
"children": [
{
"label": "Something10",
"id": 14
}
],
"label": "Something9",
"id": 7
},
{
"label": "Something8",
"id": 8
}
],
"label": "Somethin7",
"id": 3
},
{
"children": [
{
"label": "Something5",
"id": 9
},
{
"label": "Something4",
"id": 10
}
],
"label": "Something2",
"id": 4
}
],
"label": "Something1",
"id": 1
}
]
Как я могу рекурсивно искать этот dict для генерации данных Graphviz следующим образом:
Something1->Something2
Something1->Something7
Так, например, список под названием edges = []
и добавить к нему некоторые данные в виде элементов (только метки):
[("Something1", "Something2"), ("Something1", "Something7")]
После создания данных я могу просто сгенерировать объект в Graphviz (Generate PNG Image), представляющий древовидную структуру предоставленного словаря.
Если вы хотите сделать это рекурсивно, у вас может быть функция, которая генерирует ребро из узла, которое передается каждому из его дочерних элементов, а также вызывает себя для каждого из дочерних элементов. Затем все, что вам нужно сделать, это вызвать его для каждого узла в корневом списке (и вам нужно собрать все сгенерированные ребра в список). Это можно реализовать следующим образом (root
хранит ваши данные):
def get_edges(node):
if "children" not in node: # ensure the node has children
return []
label = node["label"]
children = node["children"]
result = [(label, c["label"]) for c in children] # create the edges
for c in children:
result.extend(get_edges(c)) # travers the tree recursively and collect all edges
return result
edges = sum(map(get_edges, root), []) # create and combine all the edge lists
Запуск этого кода с предоставленными вами данными дает следующее:
[('Something1', 'Something2'), ('Something1', 'Somethin7'),
('Something1', 'Something2'), ('Something2', 'Something18'),
('Something2', 'Something14'), ('Something18', 'Something20'),
('Something18', 'Something19'), ('Something14', 'Something15'),
('Somethin7', 'Something9'), ('Somethin7', 'Something8'),
('Something9', 'Something10'), ('Something2', 'Something5'),
('Something2', 'Something4')]
Я думаю, это происходит потому, что не всегда узел содержит «дочерний» ключ.
Я добавил проверку, чтобы убедиться, что у узла есть дочерние элементы. Но это решает другую проблему, которую имел код (если у узла нет дочерних узлов, python выдаст вам KeyError: 'children'
, а не TypeError
, который вы описали). Я бы предположил, что в ваших данных есть узел, у которого есть дочерний элемент, который является только строкой, а не словарем. Я протестировал код с предоставленными вами данными и добавил результаты к своему ответу.
Большое спасибо! Выяснил похожую вещь: если не дети: return [].
К сожалению, он возвращает TypeError: строковые индексы должны быть целыми числами