迭代更新scalaz树

迭代更新scalaz树,scala,scalaz,zipper,Scala,Scalaz,Zipper,我有一个路径列表: val paths = List(List("foo"), List("bar", "a"), List("bar", "b")) 我想在scalaz树中表示: def pathsToTree(root: String, paths: List[List[String]]): Tree[String] = ??? 结果: pathsToTree("paths", paths) => "paths".node("foo".leaf, "bar".node("a".l

我有一个路径列表:

val paths = List(List("foo"), List("bar", "a"), List("bar", "b"))
我想在scalaz树中表示:

def pathsToTree(root: String, paths: List[List[String]]): Tree[String] = ???
结果:

pathsToTree("paths", paths)

=> "paths".node("foo".leaf, "bar".node("a".leaf, "b".leaf))
我从中读过一些关于
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
但这似乎效率很低。

这是通用生成器:

  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)): _*)
    }
所以

屈服

"root"
|
+- "foo"
|
`- "bar"
   |
   +- "b"
   |  |
   |  `- "c"
   |
   `- "a"
println(addPath(Seq(“foo”,“baz”),tree).drawTree)
prints

"root"
|
+- "foo"
|  |
|  `- "baz"
|
`- "bar"
   |
   +- "b"
   |  |
   |  `- "c"
   |
   `- "a"

回答得很好。非常感谢。请注意,如果存在children.exists(uu.rootLabel==path.head),则在位于
的addPath中缺少一个
。我无法编辑,因为编辑必须更改超过6个字符:(
"root"
|
+- "foo"
|  |
|  `- "baz"
|
`- "bar"
   |
   +- "b"
   |  |
   |  `- "c"
   |
   `- "a"