我有一个路径列表:
val paths = List(List("foo"), List("bar", "a"), List("bar", "b"))
我想在scalaz Tree中表示:
def pathsToTree(root: String, paths: List[List[String]]): Tree[String] = ???
结果:
pathsToTree("paths", paths)
=> "paths".node("foo".leaf, "bar".node("a".leaf, "b".leaf))
我已经从http://eed3si9n.com/learning-scalaz/Tree.html读了一些关于TreeLoc
的内容,但使用左/右或儿童索引似乎相当繁琐。我想像做的那样:
paths.foldLeft(root.node()) { case (acc: Tree[String], path: List[String]) =>
acc // how to add all the items from `path` to the tree?
}
看起来我可以使用find
和setTree
或modifyTree
,但这似乎效率很低。
答案 0 :(得分:3)
这是一般建设者:
def pathTree[E](root: E, paths: Seq[Seq[E]]): Tree[E] =
root.node(paths groupBy (_.head) map {
case (parent, subpaths) => pathTree(parent, subpaths collect {
case parent +: rest if rest.nonEmpty => rest
})
} toSeq: _*)
对于在线修改,我们可以定义:
def addPath[E](path: Seq[E], tree: Tree[E]): Tree[E] = if (path.isEmpty) tree
else
tree match {
case Tree.Node(root, children) if children.exists(_.rootLabel == path.head) => root.node(
children map (subtree => if (subtree.rootLabel == path.head) addPath(path.tail, subtree) else subtree): _*
)
case Tree.Node(root, children) => root.node(children :+ path.init.foldRight(path.last.leaf)((root, sub) => root.node(sub)): _*)
}
所以
val tree = pathTree("root", List(List("foo"), List("bar", "a"), List("bar", "b", "c")))
println(tree.drawTree)
产量
"root"
|
+- "foo"
|
`- "bar"
|
+- "b"
| |
| `- "c"
|
`- "a"
和println(addPath(Seq("foo","baz"), tree).drawTree)
打印
"root"
|
+- "foo"
| |
| `- "baz"
|
`- "bar"
|
+- "b"
| |
| `- "c"
|
`- "a"