假设我有一些内部使用Tree
的{{1}}类:
Node
现在假设我想让一些节点的所有祖先都应用一些过滤功能。显而易见的方法就是这样:
class Tree {
val root = Node(null)
case class Node(parent: Node) {
val children: List[Node]
}
}
我在这个解决方案中不喜欢的是,我使用def getAncsWithFilter(filter: (Node) => Boolean): List[Node] {
var curNode = this.parent
var res: List[Node] = Nil
while (curNode != null) {
if (filter(curNode)) {
res = res :: curNode
}
curNode = curNode.parent
}
res
}
s,这段代码似乎过于命令和丑陋。我希望能够写的是这样的
var
可能是Scala吗?目前,如果我编写这样的代码,它会产生一些错误,抱怨缺少def getAncsWithFilter(filter: (Node) => Boolean): List[Node] {
val curNode = this
for (curNode <- curNode.parent if filter(curNode))
yield curNode
}
方法。如果我使用withFilter
扩展我的Node
课程,则上面的代码将返回Traversable[Node]
而非List。
答案 0 :(得分:1)
这里的问题是curNode.parent
返回单个Node
,而不是所有祖先的序列,所以你不会迭代任何东西。
您可以实现一个单独的方法ancestors
,它将返回所有祖先的序列,并且您将能够遍历它。
使用祖先进行迭代的快速方法是使用Iterator.iterate
:
def ancestors: Iterator[Node] =
Iterator.iterate(this.parent)(_.parent).takeWhile(_ != null)
getAncsWithFilter
的完整实施将成为:
def getAncsWithFilter(filter: (Node) => Boolean): List[Node] =
ancestors.filter(filter).toList
你甚至不需要使用for-comprehension(当然你仍然可以使用它,但在这种情况下,代码在我看来会变得更加复杂)。
答案 1 :(得分:0)
for-comprehension
需要在flatMap
上实施Node
。另一种选择是使用递归:
def getAncsWithFilter(filter: (Node) => Boolean, ancs: List[Node] = List()): List[Node] = {
(parent, filter(parent)) match {
case (null, _) => ancs
case (_, true) => parent.getAncsWithFilter(filter, parent :: ancs)
case (_, false) => parent.getAncsWithFilter(filter, ancs)
}
}