在树形结构中,我试图找到分支的所有叶子。这是我写的:
def leafs_of_branch(node,heads=[]):
if len(node.children()) == 0:
heads.append(str(node))
else:
for des in node.children():
leafs_of_branch(des)
return heads
leafs_of_branch(node)
我不知道为什么,但对我来说感觉不对。它有效,但我想知道是否有更好的方法来使用递归而不创建heads
参数。
答案 0 :(得分:2)
此
def leafs_of_branch(node,heads=[]):
总是一个坏主意。更好的是
def leafs_of_branch(node,heads=None):
heads = heads or []
否则你总是对leafs_of_branch使用相同的列表。在你的具体情况下,它可能是o.k.,但迟早你会遇到问题。
我建议:
def leafs_of_branch(node):
leafs = []
for des in node.children():
leafs.extend(leafs_of_branch(des))
if len(leafs)==0:
leafs.append(str(node))
return leafs
leafs_of_branch(node)
我没有做if len(node.children()==0
,而是在下降到所有(可能为零)的孩子后检查len(叶子)。因此我只调用node.children()一次。
答案 1 :(得分:1)
我相信这应该有效:
def leafs_of_branch(node):
if len(node.children()) == 0:
return [str(node)]
else:
x = []
for des in node.children():
x += leafs_of_branch(des) #x.extend(leafs_of_branch(des)) would work too :-)
return x
它不是很漂亮,可能会更加浓缩,但我试图尽可能地保留原始代码的形式,以使其显而易见。
如果您多次调用它,原始版本将无法正常工作,因为当您附加到heads
列表时,该列表实际上会在调用之间保存。
答案 2 :(得分:1)
只要递归,你就是正确的IMO;你在递归呼叫中错过了头部参数。无论如何它正在工作的原因是其他人说的,默认参数是全局的并且在调用之间重用。
如果你想避免递归altogheter,在这种情况下你可以使用队列或堆栈和循环:
def leafs_of_branch(node):
traverse = [node]
leafs = []
while traverse:
node = traverse.pop()
children = node.children()
if children:
traverse.extend(children)
else:
leafs.append(str(node))
return leafs
答案 3 :(得分:0)
首先,不要使用可变对象(列表,dicts等)作为默认值,因为默认值是全局的并且在函数调用之间重用:
def bad_func(val, dest=[]):
dest.append(val)
print dest
>>> bad_func(1)
[1]
>>> bad_func(2)
[1, 2] # surprise!
因此,随之而来的电话会让事情完全出乎意料。
至于递归问题,我会像这样重写:
from itertools import chain
def leafs_of_branch(node):
children = node.children()
if not children: # better than len(children) == 0
return (node, )
all_leafs = (leafs_of_branch(child) for child in children)
return chain(*all_leafs)
答案 4 :(得分:0)
您也可以通过这种方式递归地定义迭代器。
def leafs_of_branch(node):
if len(node.children()) == 0:
yield str(node)
else:
for des in node.children():
for leaf in leafs_of_branch(des):
yield leaf
leafs = list(leafs_of_branch(node))