Scala:用于理解迭代树节点父节点

时间:2018-01-18 22:54:52

标签: scala

假设我有一些内部使用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。

2 个答案:

答案 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)
  }
}