Python 展平包含父/子节点的树并返回所有节点

Python 展平包含父/子节点的树并返回所有节点,python,recursion,tree,Python,Recursion,Tree,可能太晚了,但在问题解决之前我无法入睡: 我有一棵树和一些父母,他们有孩子,他们也有孩子等等 现在我需要一个函数来从树中获取所有节点 这是目前有效的方法,但只有一个深度: def nodes_from_tree(tree, parent): r = [] if len(tree.get_children(parent)) == 0: return parent for child in tree.get_children(parent):

可能太晚了,但在问题解决之前我无法入睡:

我有一棵树和一些父母,他们有孩子,他们也有孩子等等

现在我需要一个函数来从树中获取所有节点

这是目前有效的方法,但只有一个深度:

def nodes_from_tree(tree, parent):
    r = []
    if len(tree.get_children(parent)) == 0:
        return parent
    for child in tree.get_children(parent):
        r.append(nodes_from_tree(tree, child))
    return r
然后我尝试传递
r
,以便它记住子节点,但我多次使用该函数,
r
累积存储所有节点,尽管我将其设置为
r=[]

def nodes_from_tree(tree, parent, r=[]):
    r = []
    if len(tree.get_children(parent)) == 0:
        return parent
    for child in tree.get_children(parent):
        r.append(nodes_from_tree(tree, child, r))
    return r
编辑:这是树结构:

parent1    parent2    parent3
   |          |          |
   |          |          |
 child        |          |
              |          |
      +--------------+   |
      |       |      |   |
    child   child  child |
      |                  |
  +---+---+              |
child   child        +---+---+
                     |       |
                   child     |
                             |
                       +-----+-----+-----+
                       |     |     |     |
                     child child child child
可用方法:

tree.get_parents()       # returns the nodes of the very top level
tree.get_children(node)  # returns the children of parent or child

如果我理解您的问题,您希望创建一个包含树中所有值的平面列表,在这种情况下,由元组表示的树将起作用,如下所示:

def nodes_from_tree(tree,nodes=list()):
    if isinstance(tree,tuple):
        for child in tree:
            nodes_from_tree(child,nodes=nodes)
    else:
        nodes.append(tree)

mynodes = []
tree = (('Root',
        ('Parent',(
            ('Child1',),
            ('Child2',)
            )
        ),
        ('Parent2',(
            ('child1',(
                ('childchild1','childchild2')
            )),
            ('child2',),
            ('child3',)
        )),
        ('Parent3',(
            ('child1',),
            ('child2',(
                ('childchild1',),
                ('childchild2',),
                ('childchild3',),
                ('childchild4',)
            ))
        ))
    ))
nodes_from_tree(tree,nodes=mynodes)
print(mynodes)
产生

['Root', 'Parent', 'Child1', 'Child2', 'Parent2', 'child1', 'childchild1', 'childchild2',
 'child2', 'child3', 'Parent3', 'child1', 'child2', 'childchild1', 'childchild2', 'childchild3', 'childchild4']

如果我理解您的问题,您希望创建一个包含树中所有值的平面列表,在这种情况下,由元组表示的树将起作用,如下所示:

def nodes_from_tree(tree,nodes=list()):
    if isinstance(tree,tuple):
        for child in tree:
            nodes_from_tree(child,nodes=nodes)
    else:
        nodes.append(tree)

mynodes = []
tree = (('Root',
        ('Parent',(
            ('Child1',),
            ('Child2',)
            )
        ),
        ('Parent2',(
            ('child1',(
                ('childchild1','childchild2')
            )),
            ('child2',),
            ('child3',)
        )),
        ('Parent3',(
            ('child1',),
            ('child2',(
                ('childchild1',),
                ('childchild2',),
                ('childchild3',),
                ('childchild4',)
            ))
        ))
    ))
nodes_from_tree(tree,nodes=mynodes)
print(mynodes)
产生

['Root', 'Parent', 'Child1', 'Child2', 'Parent2', 'child1', 'childchild1', 'childchild2',
 'child2', 'child3', 'Parent3', 'child1', 'child2', 'childchild1', 'childchild2', 'childchild3', 'childchild4']

我认为你的问题在于你积累的东西不正确

首先,如果您点击一个中间节点,每个子节点都应该返回一个列表,但您是在
附加该列表,而不是
扩展该列表。因此,您将得到类似于
[[1,2],[3,4]
的内容,而不是
[1,2],[3,4]
——换句话说,您只是将其转换为列表树列表,而不是平面列表。将此更改为
extend

其次,如果你点击了一个叶节点,你根本不会返回一个列表,只返回父节点。将此更改为
返回[parent]

第三,如果你点击一个中间节点,你不会在任何地方包含
parent
,所以你只会得到叶子。但是你想要所有的节点。因此,将
r=[]
更改为
r=[parent]

对于最后一个更改,您根本不需要
if
块。如果没有子级,循环将发生0次,并且您将按原样返回
[parent]
,这完全是您想要的

因此:


同时,虽然这个版本可以工作,但仍然很混乱。你混合了两种不同的递归风格。将累加器沿链条向下传递,并在向下的过程中添加,这是一种方法;另一种方法是在链的上游返回值,在上游累积结果。你每个都做了一半

事实证明,您执行上游递归的方式是使下游递归完全无效。虽然您将
r
向下传递给每个孩子,但您从不修改它,甚至不使用它;您只需创建一个新的
r
列表并返回该列表

解决此问题的最简单方法是删除累加器参数:

def nodes_from_tree(tree, parent):
    r = [parent]
    for child in tree.get_children(parent):
        r.extend(nodes_from_tree(tree, child))
    return r

(值得注意的是,分支递归只能在下游累加器样式而不是上游聚集样式下进行尾部调用优化。但这在Python中并不重要,因为Python不进行尾部调用优化。因此,编写对您更有意义的分支递归。)我认为你的问题在于你积累的东西不正确

首先,如果您点击一个中间节点,每个子节点都应该返回一个列表,但您是在
附加该列表,而不是
扩展该列表。因此,您将得到类似于
[[1,2],[3,4]
的内容,而不是
[1,2],[3,4]
——换句话说,您只是将其转换为列表树列表,而不是平面列表。将此更改为
extend

其次,如果你点击了一个叶节点,你根本不会返回一个列表,只返回父节点。将此更改为
返回[parent]

第三,如果你点击一个中间节点,你不会在任何地方包含
parent
,所以你只会得到叶子。但是你想要所有的节点。因此,将
r=[]
更改为
r=[parent]

对于最后一个更改,您根本不需要
if
块。如果没有子级,循环将发生0次,并且您将按原样返回
[parent]
,这完全是您想要的

因此:


同时,虽然这个版本可以工作,但仍然很混乱。你混合了两种不同的递归风格。将累加器沿链条向下传递,并在向下的过程中添加,这是一种方法;另一种方法是在链的上游返回值,在上游累积结果。你每个都做了一半

事实证明,您执行上游递归的方式是使下游递归完全无效。虽然您将
r
向下传递给每个孩子,但您从不修改它,甚至不使用它;您只需创建一个新的
r
列表并返回该列表

解决此问题的最简单方法是删除累加器参数:

def nodes_from_tree(tree, parent):
    r = [parent]
    for child in tree.get_children(parent):
        r.extend(nodes_from_tree(tree, child))
    return r

(值得注意的是,分支递归只能在下游累加器样式而不是上游聚集样式下进行尾部调用优化。但这在Python中并不重要,因为Python不进行尾部调用优化。因此,请编写对您更有意义的分支递归。)

树的格式如何,即:
(值,[(value,[…]),(child2),…])
?请参阅我更新的问题!它返回的是什么,您期望得到什么?(您可能希望回答一个比粘贴为ASCII艺术的示例小得多的示例…)我猜您的问题是使用了
append
,您的意思是
extend
,因此您最终返回的是列表树列表,而不是平面列表。此外,您对父级的逻辑是错误的。您可能希望先执行
r=[parent]
,然后再将其添加到末尾。(然后您根本不需要
if
语句。如果没有子级,您就不会在末尾添加任何内容,只需按原样返回
parent
)树的格式是什么,即:
(value,[(value,[…]),(child2),…)
?请参阅我的