这是我上一个问题的后续行动。我想热切地(而不是懒惰)线性化XML树。为简单起见,我假设XML树是Elem
节点的树,因此我将XML转换为Elem
的序列。
import scala.xml.{Elem, Node}
import PartialFunction._
def linearize(node: Node): List[Node] = {
val children = node.child.filter(cond(_) {case _: Elem => true}).toList
children match {
case Nil => List(node)
case list => node :: list.flatMap(linearize)
}
}
看起来很有效,但我不喜欢val children = ...
您如何建议更改/修复它?
答案 0 :(得分:2)
由于您已经将node.child
转换为List
,因此您无需在其上进行匹配,您可以直接使用flatMap,因为如果child
为空,它将返回Nil 。以下代码产生与简单测试用例的解决方案相同的结果。
import scala.xml.{Elem, Node}
import PartialFunction._
def linearize(node: Node): List[Node] = {
node :: node.child.flatMap {
case e: Elem => linearize(e)
case _ => Nil
}.toList
}
答案 1 :(得分:1)
您可以depth-first and breath-first方式遍历树。我已经为这两种模式创建了功能。两者都是尾递归的,所以你可以牺牲堆来节省一些堆栈帧。
import scala.xml.{ Elem, Node }
def linearizeDepthFirst(node: Node): List[Node] = {
@annotation.tailrec
def loop(toVisit: Vector[Node], result: Vector[Node]): List[Node] = {
if (toVisit.isEmpty) {
result.toList
} else {
val children = toVisit.head.collect({ case e: Elem => e }).toVector
loop(children ++ toVisit.tail, result ++ children)
}
}
loop(Vector(node), Vector(node))
}
def linearizeBreadthFirst(node: Node): List[Node] = {
@annotation.tailrec
def loop(toVisit: Vector[Node], result: Vector[Node]): List[Node] = {
if (toVisit.isEmpty) {
result.toList
} else {
val children = toVisit.head.collect({ case e: Elem => e }).toVector
loop(toVisit.tail ++ children, result ++ children)
}
}
loop(Vector(node), Vector(node))
}