我想使下面的递归方法是尾递归的,但我不确定这是否可行,因为该方法在flatMap
内调用自己。
@tailrec
def loop(nodes: List[Node], myNodes: List[MyNode]): List[MyNode] = nodes match {
case Nil => myNodes
case _ =>
nodes.flatMap { n =>
val myNode = MyNode(data = n.data)
loop(n.getChildNodes().toList, myNode :: myNodes)
}
}
loop(nodes, List())
不幸的是,我收到以下错误:
could not optimize @tailrec annotated method loop: it contains a recursive call not in tail position
[error] case _ =>
[error] ^
[error] one error found
答案 0 :(得分:4)
正如@SteffenSchmitz所说,你无法在flatMap
内进行递归调用。实际上,在列表至少有两个Node
s的情况下,您的方法将至少有两次调用自身,因此它不能是tailrec。但是,您可以使用尾递归来执行与逻辑相同的操作。
您的代码正在做什么,就是将Node
中nodes
中的数据复制到List[MyNode]
中,这似乎是一种树形结构。{/ p>
最后,您将获得原始树的每个叶子的所有祖先的列表。
例如,如果你的树是
A
/ \
B C
/ \
D E
您将获得List(B, A, D, C, A, E, C, A)
(此处,我假设data
为Char
,为简单起见)。第一个B, A
是B
的祖先,下一个D, C, A
是D
的祖先,E
的最后一个。
您可以使用以下tailrec执行相同操作:
@tailrec
def tailrecLoop(nodesWithAncestors: List[(Node, List[MyNode])], acc: List[MyNode]): List[MyNode] = {
nodesWithAncestors.headOption match {
case None => acc
case Some((node, ancestors)) if node.getChildNodes().toList.isEmpty =>
loop(nodes.tail, acc ::: myNode :: ancestors)
case Some((node, ancestors)) =>
val myNode = MyNode(data = node.data)
val childrenWithAncestors =
node.getChildNodes().toList.map(_ -> (myNode :: ancestors))
loop(childrenWithAncestors ++ nodes.tail, acc)
}
}
def loop(nodes: List[Node]) = tailrecLoop(nodes.map(_ -> Nil), Nil)
这里的关键是将未处理的节点(nodesWithAncestors
)放入队列中,稍后通过子调用处理。
答案 1 :(得分:1)
无法在flatmap中进行尾递归调用。函数中的最后一个调用必须是loop()。