Convertendo lista de árvore para dict hierarquia
-
09-09-2019 - |
Pergunta
Eu tenho uma lista de elementos com attrs:. Pais, nível, is_leaf_node, is_root_node, is_child_node
Eu quero converter essa lista para dict hierarquia. Exemplo de Dict saída:
{
'Technology':
{
'Gadgets':{},
'Gaming':{},
'Programming':
{
'Python':{},
'PHP':{},
'Ruby':{},
'C++':{}
},
'Enterprise':{},
'Mac':{},
'Mobile':{},
'Seo':{},
'Ui':{},
'Virtual Worlds':{},
'Windows':{},
},
'News':{
'Blogging':{},
'Economics':{},
'Journalism':{},
'Politics':{},
'News':{}
},}
Eu não sei algoritmo. Como fazer isso?
Solução
Aqui está uma versão menos sofisticada, recursivo como chmod 700 descrito. Completamente testado é claro:
def build_tree(nodes):
# create empty tree to fill
tree = {}
# fill in tree starting with roots (those with no parent)
build_tree_recursive(tree, None, nodes)
return tree
def build_tree_recursive(tree, parent, nodes):
# find children
children = [n for n in nodes if n.parent == parent]
# build a subtree for each child
for child in children:
# start new subtree
tree[child.name] = {}
# call recursively to build a subtree for current node
build_tree_recursive(tree[child.name], child, nodes)
Outras dicas
Tudo sem um pai é o seu nível mais alto, então fazer essas dicts primeiro. Em seguida, fazer uma segunda passagem através de sua matriz para encontrar tudo com um dos pais nesse nível superior, etc ... Pode ser escrito como um loop ou uma função recursiva. Você realmente não precisa de nenhum das informações fornecidas, além de "pai".
Parece que você está querendo basicamente a fazer é uma variante do topológica classificação . O algoritmo mais comum para isso é o algoritmo de remoção fonte. O pseudocódigo seria algo parecido com isto:
import copy
def TopSort(elems): #elems is an unsorted list of elements.
unsorted = set(elems)
output_dict = {}
for item in elems:
if item.is_root():
output_dict[item.name] = {}
unsorted.remove(item)
FindChildren(unsorted, item.name, output_dict[item.name])
return output_dict
def FindChildren(unsorted, name, curr_dict):
for item in unsorted:
if item.parent == name:
curr_dict[item.name] = {}
#NOTE: the next line won't work in Python. You
#can't modify a set while iterating over it.
unsorted.remove(item)
FindChildren(unsorted, item.name, curr_dict[item.name])
Isto, obviamente, é quebrado em um par de lugares (pelo menos como código Python real). No entanto, espero , que lhe dará uma idéia de como o algoritmo funciona. Note que este irá falhar terrivelmente se há um ciclo nos itens que você tem (digamos um item tem alínea b como um pai quando o item b tem um item como um pai). Mas, então, que provavelmente seria impossível representar no formato que você está querendo fazer de qualquer maneira.
Algo simples como este trabalho poder:
def build_tree(category_data):
top_level_map = {}
cat_map = {}
for cat_name, parent, depth in cat_data:
cat_map.setdefault(parent, {})
cat_map.setdefault(cat_name, {})
cat_map[parent][cat_name] = cat_map[cat_name]
if depth == 0:
top_level_map[cat_name] = cat_map[cat_name]
return top_level_map
uma forma recursiva bom para fazê-lo:
def build_tree(elems):
elem_with_children = {}
def _build_children_sub_tree(parent):
cur_dict = {
'id': parent,
# put whatever attributes here
}
if parent in elem_with_children.keys():
cur_dict["children"] = [_build_children_sub_tree(cid) for cid in elem_with_children[parent]]
return cur_dict
for item in elems:
cid = item['id']
pid = item['parent']
elem_with_children.setdefault(pid, []).append(cid)
res = _build_children_sub_tree(-1) # -1 is your root
return res