Converting tree list to hierarchy dict

前端 未结 5 1758
日久生厌
日久生厌 2021-02-06 06:39

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:

相关标签:
5条回答
  • 2021-02-06 07:12

    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.

    0 讨论(0)
  • 2021-02-06 07:13

    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
    
    0 讨论(0)
  • 2021-02-06 07:20

    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".

    0 讨论(0)
  • 2021-02-06 07:33

    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)
    
    0 讨论(0)
  • 2021-02-06 07:37

    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
    
    0 讨论(0)
提交回复
热议问题