Преобразование списка деревьев в иерархию - PullRequest
8 голосов
/ 16 апреля 2009

У меня есть список элементов с attrs: parent, level, is_leaf_node, is_root_node, is_child_node.

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

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

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

Ответы [ 5 ]

12 голосов
/ 16 апреля 2009

Ниже описана менее сложная, рекурсивная версия, такая как 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)
2 голосов
/ 16 апреля 2009

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

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 в качестве родителя). Но тогда это, вероятно, было бы невозможно представить в формате, который вы хотите сделать в любом случае.

2 голосов
/ 16 апреля 2009

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

0 голосов
/ 04 мая 2017

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

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 голосов
/ 17 апреля 2009

Нечто подобное может работать:

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