def flat_to_hierarchical(flat_tree):
    """Перестраивает дерево в виде списка в иерархическую струтуру.
    У элементов списка flat_tree должны быть ключи id и parent_id.
    Пример в тестах.

    """
    root = flat_tree[0]
    index = {root['id']: root}

    for group in flat_tree[1:]:

        parent = index[group['parent_id']]
        descendants = parent.setdefault('descendants', [])
        descendants.append(group)

        index[group['id']] = group

    return root


def flat_to_hierarchical_using_level(flat_tree):
    """Перестраивает дерево в виде списка в иерархическую струтуру.
    У элементов списка flat_tree должен быть ключ level.
    Пример в тестах.

    """
    def append_descendant_to_last_parent(descendant):
        current_parent = parents_stack[-1]
        descendants = current_parent.setdefault('descendants', [])
        descendants.append(descendant)

    def get_last_parent_level():
        return parents_stack[-1]['level']

    root = flat_tree[0]
    other_tree = flat_tree[1:]

    parents_stack = []
    previous_node = root
    for node in other_tree:
        current_level = node['level']
        previous_level = previous_node['level']

        if current_level > previous_level:
            # нашли первого потомка у предыдущей ноды --
            # кладем ее в стек родителей
            parents_stack.append(previous_node)
        elif current_level < previous_level:
            # у текущего родителя потомки кончились,
            # найдем в стеке родителя текущей ноды
            # (у которого уровень на 1 меньше)
            current_node_parent_level = current_level - 1
            last_parent_level = get_last_parent_level()
            while last_parent_level != current_node_parent_level:
                parents_stack.pop()
                last_parent_level = get_last_parent_level()

        # нужно положить положить потомка в список с потомками текущего родителя
        append_descendant_to_last_parent(node)
        previous_node = node

    return root
