如何在Python中将嵌套列表转换为树形表示?

-3 投票
2 回答
60 浏览
提问于 2025-04-14 15:40

我正在尝试用 Python 创建一个树形可视化工具,使用的是嵌套列表,并且不想用任何特别的库。

我遇到的问题是,虽然树的节点存储得很正确,但打印出来的顺序却是按照输入的顺序。

我尝试实现一个递归的解决方案,这个方案对像 [42,['a','b']] 这样的输入有效——在这里 42 是根节点,而 'a''b' 是它的子节点。不过,我也可能会收到像 [['a','b'], 42] 这样的输入,在这种情况下 42 仍然是根节点。下面是代码和示例输出。

这是我尝试实现的解决方案。

class TreeNode:
    def __init__(self, data):
        self.data = data
        self.children = []

    def add_child(self, child_node):
        self.children.append(child_node)

def assign_tree_nodes(input_data):
    if isinstance(input_data, list):
        node = TreeNode(None)
        for item in input_data:
            child_node = assign_tree_nodes(item)
            node.add_child(child_node)
        return node
    else:
        return TreeNode(input_data)

def print_tree(node, indent=0):
    if node.data is not None:
        print("  " * indent + str(node.data))
    if node.children:
        for child in node.children:
            print_tree(child, indent + 1)

# Prompt the user for input
input_data = eval(input("INPUT:\n"))

# Assign tree nodes
root_node = assign_tree_nodes(input_data)


# Print out the tree
for child in root_node.children:
    print_tree(child)

这个代码对像 [42,['a','b']] 这样的输入有效,输出结果是

42
  a
  b

但是对于像 [['a','b'],42] 这样的输入,输出结果是

  a
  b
42

2 个回答

0

如果我们在处理节点数据时,按照类型重新排序这些数据,会发生什么呢:

def assign_tree_nodes(input_data):
    if isinstance(input_data, list):
        data, children = sorted(input_data, key=lambda x: [int, list].index(type(x)))

        node = TreeNode(data)

        for child in children:
            node.add_child(assign_tree_nodes(child))
    else:
        node = TreeNode(input_data)

    return node

def print_tree(node, indent=0):
    print("  " * indent, node.data, sep='')

    for child in node.children:
        print_tree(child, indent + 1)

example = [6, [[[[1, [2, 3]], [[-43, 44], 42]], 4], 5]]

print_tree(assign_tree_nodes(example))

输出结果

% python3 test.py
6
  4
    1
      2
      3
    42
      -43
      44
  5
% 
1

我稍微玩了一下你的代码,发现其实发生的事情是“根节点”的数据是 None,而看起来像是节点数据的其实是一个有数据但没有子节点的子节点。

你可能想要的是这个:

    def add_child(self, child_node):
        if child_node.data is not None and child_node.children == []:
            # whoops, it's a leaf
            self.data = child_node.data
        else:
            self.children.append(child_node)

如果你知道输入总是会是包含两个元素的列表,并且最多只有一个子列表表示子节点的话,这样是可以工作的。

比如在 @trincot 的例子 [['a', [9], 'b'],42] 中,具体怎么处理取决于这是否有意义。你可能只需要这样做,确保叶子节点总是排在子节点列表的最前面:

    def add_child(self, child_node):
        if child_node.data:
            # it's a leaf so it comes first
            self.children.insert(0, child_node)
        else:
            # it's a branch node
            self.children.append(child_node)

你可以选择其中一个。或者也许其他人会给出不同的答案。

撰写回答