I have a list of elements with attrs: parent, level, is_leaf_node, is_root_node, is_child_node.
I want to convert this list to hierarchy dict. Example of output dict:
It sounds like what you're basically wanting to do is a variant of topological sorting. The most common algorithm for this is the source removal algorithm. The pseudocode would look something like this:
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])
This obviously is broken in a couple of places (at least as actual Python code). However, hopefully that will give you an idea of how the algorithm will work. Note that this will fail horribly if there's a cycle in the items you have (say item a has item b as a parent while item b has item a as a parent). But then that would probably be impossible to represent in the format you're wanting to do anyway.
a nice recursive way to do it:
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
Everything without a parent is your top level, so make those dicts first. Then do a second pass through your array to find everything with a parent at that top level, etc... It could be written as a loop or a recursive function. You really don't need any of the provided info besides "parent".
Here's a less sophisticated, recursive version like chmod 700 described. Completely untested of course:
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)
Something simple like this might work:
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