[英]Flattening a tree with parents/children and return all nodes
可能为时已晚,但是直到解决后我才能入睡:
我有一棵树,有一些父母,他们有孩子,也有孩子等。
现在,我需要一个函数来从树中获取所有节点。
这是当前有效的方法,但仅具有一个深度级别:
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']
我认为您的问题仅仅是您不正确地积累了东西。
首先,如果您击中一个中间节点,则每个子节点都应返回一个列表,但是您要append
该列表而不是extend
它。 因此,您将获得[[1, 2], [3, 4]]
类的东西,而不是[1, 2, 3, 4]
[[1, 2], [3, 4]]
-换句话说,您只是将其转换为列表- -list树,而不是平面列表。 将其更改为extend
。
其次,如果您命中了一个叶子节点,那么您根本就不会返回任何列表,而只是返回parent
。 更改为return [parent]
。
第三,如果您击中一个中间节点,那么您将不会在任何地方包含parent
节点,因此最终只会留下叶子。 但是您需要所有节点。 因此将r = []
更改为r = [parent]
。
有了最后的更改,您根本不需要if
块。 如果没有子代,则该循环将发生0次,最终您将按原样返回[parent]
。
所以:
def nodes_from_tree(tree, parent, r=[]):
r = [parent]
for child in tree.get_children(parent):
r.extend(nodes_from_tree(tree, child, r))
return r
同时,尽管此版本可以使用 ,但仍然感到困惑。 您正在混合两种不同的递归样式。 一种将累加器顺着链条传下来,然后再顺路加法的方法是这样做的。 另一个是返回价值链并在上升过程中累积结果。 你们每个人都做一半。
事实证明,您执行上游递归的方式是使下游递归完全无效。 当您确实将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不会进行尾调用优化。因此,请写下对您更有意义的一种。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.