Преобразование древовидного списка в иерархический словарь

StackOverflow https://stackoverflow.com/questions/757244

  •  09-09-2019
  •  | 
  •  

Вопрос

У меня есть список элементов с атрибутами:родительский, уровень, is_leaf_node, is_root_node, is_child_node.

Я хочу преобразовать этот список в иерархию.Пример вывода dict:

{
        'Technology':
            {
             'Gadgets':{},
             'Gaming':{},
             'Programming':
                {
                    'Python':{},
                    'PHP':{},
                    'Ruby':{},
                    'C++':{}
                },
             'Enterprise':{},
             'Mac':{},
             'Mobile':{},
             'Seo':{},
             'Ui':{},
             'Virtual Worlds':{},
             'Windows':{},
            },
        'News':{
            'Blogging':{},
            'Economics':{},
            'Journalism':{},
            'Politics':{},
            'News':{}
            },}

Я не знаю алгоритма.Как это сделать?

Это было полезно?

Решение

Вот описанная менее сложная рекурсивная версия, подобная chmod 700.Совершенно непроверенное конечно:

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)

Другие советы

Все, что не имеет родителя, является вашим высшим уровнем, поэтому сначала сделайте эти диктовки.Затем выполните второй проход по массиву, чтобы найти все, что имеет родительский элемент на этом верхнем уровне и т.д.Его можно записать как цикл или рекурсивную функцию.Вам действительно не нужна никакая предоставленная информация, кроме «родителя».

Похоже, то, что вы в основном хотите сделать, это вариант топологическая сортировка.Наиболее распространенным алгоритмом для этого является алгоритм удаления источника.Псевдокод будет выглядеть примерно так:

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])

Очевидно, что в нескольких местах это не работает (по крайней мере, в реальном коде Python).Однако, с надеждой это даст вам представление о том, как будет работать алгоритм.Обратите внимание, что это приведет к ужасной ошибке, если в имеющихся у вас элементах есть цикл (скажем, элемент a имеет элемент b в качестве родительского элемента, а элемент b имеет элемент a в качестве родительского элемента).Но тогда это, вероятно, будет невозможно представить в том формате, который вы хотите сделать.

Что-то простое вроде этого может сработать:

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

хороший рекурсивный способ сделать это:

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top