考虑这些案例类,其中Blog
包含Post
个,Post
包含Comment
s,然后Relation
将单个父级与a {0}}相关联单身孩子:
case class Comment(id: Int)
case class Post(id: Int, comments: List[Comment])
case class Blog(id: Int, posts: List[Post])
case class Relation[A, B](parent: A, child: B)
我要做的是递归地将这些Relations
的列表折叠到顶层parent
,从这样的东西开始(这个非嵌套结构的原因)首先,这是解析时带连接列的SQL结果的样子:
val relations = List(
Relation(Post(1, Nil), Comment(1)),
Relation(Post(1, Nil), Comment(2)),
Relation(Post(2, Nil), Comment(3)),
Relation(Post(3, Nil), Comment(4)),
Relation(Post(4, Nil), Comment(5))
)
输出应为:
List(
Post(1,List(Comment(1), Comment(2))),
Post(2, List(Comment(3), Comment(4), Comment(5)))
)
使用一个嵌套级别,这很容易:
def collapse[A, B](relations: List[Relation[A, B]])(implicit f: (A, List[B]) => A): List[A] = {
relations.groupBy(_.parent)
.mapValues(_.map(_.child))
.toList
.map(f.tupled)
}
implicit
函数需要的位置如下:
implicit def collapsePost(post: Post, comments: List[Comment]): Post = post.copy(comments = comments)
当我想添加另一层嵌套时,麻烦就开始了,B
可能会成为另一个Relation
。所以我尝试了很多这种结构的变体:
sealed abstract class Node
case class Relation[A, B <: Node](parent: A, child: B) extends Node
case class Child[B](value: B) extends Node
所以现在我试图崩溃的例子看起来更像是这样:
val relations = List(
Relation(Blog(1, Nil), Relation(Post(1, Nil), Child(Comment(1)))),
Relation(Blog(1, Nil), Relation(Post(2, Nil), Child(Comment(2)))),
Relation(Blog(1, Nil), Relation(Post(2, Nil), Child(Comment(3))))
)
所需的输出:
List(
Blog(1, List(
Post(1, List(Comment(1))),
Post(2, List(Comment(2), Comment(3)))
)
)
)
我的collapse
功能的签名保持不变(暂时)。我可以在parent
参数的relations
上进行分组,但后来我陷入了递归步骤。在collapse
中的函数链中的某个点,我将Map[A, List[Node]]
,其中List[Node]
是List[Relation[B, ?]]
或List[Child[B]]
。问号说明我未能继续前进。我已尝试将TypeTag
引入模式匹配列表,因为类型已被删除,但编译器仍会抱怨Relation
的第二个类型参数。
即。如果list
是List[Node]
,那么
list match {
case rel @ List[Relation[B, _]] => collapse(rel) // Complains about missing TypeTag in recursive call to `collapse`
case children @ List[Child[B]] => children
}
在这样的递归定义的类中是否存在丢失类型参数的方法(如果可能,不需要反射)?或许我完全走错了路。
答案 0 :(得分:1)
这是一个不使用Child
类或需要更改collapse
的解决方案:
implicit def collapseBlog(blog: Blog, relations: List[Relation[Post, Comment]])(implicit f: (Post, List[Comment]) => Post) = {
blog.copy(posts = collapse(relations))
}
我们正在利用递归隐式解析 - collapseBlog
将使用collapsePost
作为其隐式,并且它们可以一起折叠两级深层结构。基本上,collapse(relations)
在隐式解决后变为collapse(relations)((x, y) => collapseBlog(x, y)(collapsePost))
。