这是parent pointer tree 数据结构。类似的东西可能会有所帮助:
import scala.xml._
case class Category(parentId: Int, id: Int, name: String, order: Ordering[Category])
val rootOrder = Ordering.by[Category, String](_.name) //ordering example
def unflatten(c: List[Category])(implicit rootOrder: Ordering[Category]): NodeSeq = <root>{
unflatten(0, c.groupBy(_.parentId))
}</root>
def unflatten(id: Int, all: Map[Int, List[Category]])(implicit order: Ordering[Category]): NodeSeq =
all.get(id).map(_.sorted.map(c =>
<category id = {c.id.toString} name = {c.name}>{
unflatten(c.id, all)(c.order) // attaching sub-elements
}</category>)).getOrElse(Nil) // or nothing
scala> unflatten(List(Category(0, 1, "aaa", rootOrder), Category (1,2, "bbb", rootOrder), Category(0, 3, "aaa", rootOrder)))(rootOrder)
res11: scala.xml.NodeSeq = <root><category id="1" name="aaa"><category id="2" name="bbb"></category></category><category id="3" name="aaa"></category></root>
Ordering 应作为隐式参数传递给 sorted 函数。
它不是尾递归,但需要一个大小等于结构中最大嵌套级别的堆栈 - 因为您在内存中有一个完整的类别列表并且它适合 - 堆栈不会超过这个。如果您需要更具可扩展性的东西 - 最好使用您的数据库进行非扁平化,例如 Oracle 中的 CONECT BY:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm
您还可以使用groupBy 从叶子开始遍历树(它将是尾递归的),例如:
import scala.annotation._
type Cat = Category
case class Node(cat: Cat, children: List[Node]) {
/** can't be added as implicit because of potential stackoverflow */
val xml: scala.xml.NodeSeq = <category id = {cat.id.toString} name = {cat.name}>{
implicit val sort = cat.order.on[Node](_.cat)
children.sorted.map(_.xml) // attaching sub-elements
}</category>
}
@tailrec def unflatten(leafs: List[Node], acc: Map[Int, Node]) : List[Node] = {
val parents =
for((id, children) <- leafs.groupBy(_.cat.parentId);
p <- acc.get(id))
yield id -> Node(p.cat, (p.children ++ children))
if (parents.nonEmpty) unflatten(parents.values.toList, acc ++ parents) else all.values.toList.filter(_.cat.parentId == 0)
}
def unflatten(cats: List[Cat]): List[Node] = {
val grouped = cats.groupBy(_.id).mapValues(_.map(Node(_, Nil)).head) //Map[Int, Node]
val byParent = cats.groupBy(_.parentId)
val leafs = grouped.filter(x => !byParent.contains(x._1)).values.toList //no children
unflatten(leafs, grouped)
}
def unflattenXml(cats: List[Cat])(implicit ord: Ordering[Node] = rootOrder.on(_.cat)) =
<root>{unflatten(cats).sorted.map(_.xml)}</root>
scala> unflatten(List(Category(0, 1, "aaa", rootOrder), Category (1,2, "bbb", rootOrder), Category(0, 3, "aaa", rootOrder)))
res15: List[Node] =
List(Node(Category(0,1,aaa,scala.math.Ordering$$anon$9@2412c5e9),
List(Node(Category(1,2,bbb,scala.math.Ordering$$anon$9@2412c5e9),List()))),
Node(Category(0,3,aaa,scala.math.Ordering$$anon$9@2412c5e9),List()))
scala> unflattenXml(List(Category(0, 1, "aaa", rootOrder), Category (1,2, "bbb", rootOrder), Category(0, 3, "aaa", rootOrder)))
res29: scala.xml.Elem = <root><category id="1" name="aaa"><category id="2" name="bbb"></category></category><category id="3" name="aaa"></category></root>
如果您正在寻找来源: