【问题标题】:constructing a tree view from a nested list with duplicate subtrees (using anytree/treelib)从具有重复子树的嵌套列表构造树视图(使用 anytree/treelib)
【发布时间】:2019-06-17 18:15:01
【问题描述】:

我有一个嵌套列表,如下所示:

lst = [['a', 'b', 'e'],      # this e is the branch of b
       ['a', 'f', 'e'],      # this e is the branch of f,
       ['a', 'h', 'i i i']]  # string with spaces

我想构建一棵树:

a
├── b
│   └── e
├── f
|   └── e
└── h
    └── i i i

我想使用以下两个包中的任何一个:treelibanytree。我已经阅读了很多帖子并尝试了许多不同的方法,但都没有成功。

更新:

我想出了下面的方法,但是我现在遇到的问题是

  1. 不能保证分支的垂直顺序(例如,“b”、“f”、“h”)(当我在一个列表中有很多列表时)。
  2. “e”作为“f”的一个分支不会出现
from treelib import Node, Tree

# make list flat
lst = sum([i for i in lst], [])

tree = Tree()
tree_dict = {}

# create root node
tree_dict[lst[0]] = tree.create_node(lst[0])

for index, item in enumerate(lst[1:], start=1):
    if item not in tree_dict.keys():
        partent_node = tree_dict[lst[index-1]]
        tree_dict[item] = tree.create_node(item, parent=partent_node)

tree.show()

【问题讨论】:

    标签: python python-3.x tree treeview anytree


    【解决方案1】:

    我查看了anytree 并想出了这个:

    from anytree import Node, RenderTree
    
    lst = [["a", "b", "c", "e"], ["a", "b", "f"], ["a", "b", "c", "g", "h"], ["a", "i"]]
    
    
    def list_to_anytree(lst):
        root_name = lst[0][0]
        root_node = Node(root_name)
        nodes = {root_name: root_node}  # keeping a dict of the nodes
        for branch in lst:
            assert branch[0] == root_name
            for parent_name, node_name in zip(branch, branch[1:]):
                node = nodes.setdefault(node_name, Node(node_name))
                parent_node = nodes[parent_name]
                if node.parent is not None:
                    assert node.parent.name == parent_name
                else:
                    node.parent = parent_node
        return root_node
    
    
    anytree = list_to_anytree(lst)
    for pre, fill, node in RenderTree(anytree):
        print(f"{pre}{node.name}")
    

    这里没有发生太多事情。我只是将您的列表转换为 anytree 节点(并且assert 列表表示在执行此操作时有效)。我在nodes 中保留了我已经拥有的节点的字典。

    输出确实是

    a
    ├── b
    │   ├── c
    │   │   ├── e
    │   │   └── g
    │   │       └── h
    │   └── f
    └── i
    

    如果您有多个同名节点,则不能使用上面的dict;您需要从根节点遍历子节点:

    def list_to_anytree(lst):
        root_name = lst[0][0]
        root_node = Node(root_name)
        for branch in lst:
            parent_node = root_node
            assert branch[0] == parent_node.name
            for cur_node_name in branch[1:]:
                cur_node = next(
                    (node for node in parent_node.children if node.name == cur_node_name),
                    None,
                )
                if cur_node is None:
                    cur_node = Node(cur_node_name, parent=parent_node)
                parent_node = cur_node
        return root_node
    

    你的例子

    lst = [
        ["a", "b", "e"],  # this e is the branch of b
        ["a", "f", "e"],  # this e is the branch of f,
        ["a", "h", "i i i"],
    ]
    
    anytree = list_to_anytree(lst)
    for pre, fill, node in RenderTree(anytree):
        print(f"{pre}{node.name}")
    

    然后给出:

    a
    ├── b
    │   └── e
    ├── f
    │   └── e
    └── h
        └── i i i
    

    【讨论】:

    • 嗨,伙计。由于某些原因,我不断收到带有空格的字符串的 AssertError。你能看看我更新的问题吗?
    • 嗨@史蒂文!问题不在于带有空格的节点,而是您有两个名为 e 的节点具有不同的父节点。如果不需要允许,我需要稍微更改逻辑(我的nodes 字典将不起作用...)。
    • 嗨,伙计。有没有使用 next() 来缩短代码的替代方法?
    • 不是我所知道的...参见例如这个:stackoverflow.com/questions/2361426/…。您可以将其打包成一个函数(将其分解):def next_child(cur_node_name, parent_node): return next(...)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    相关资源
    最近更新 更多