迭代更新scalaz树

时间:2015-05-08 00:39:45

标签: scala scalaz zipper

我有一个路径列表:

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?
}

看起来我可以使用findsetTreemodifyTree,但这似乎效率很低。

1 个答案:

答案 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"