一种将父级和子级分组到List [(Parent,List [Child])]的优雅方法

时间:2018-08-23 20:48:48

标签: scala functional-programming

我有这样的结构:

case class Parent(id : Option[Long], name : String)
case class Child(id : Option[Long], parentId : Long, name : String)

val parents : List[Parent] = List(
  Parent(Some(1),"John"), 
  Parent(Some(2),"Jake"), 
  Parent(Some(3),"Tamara"))

val children : List[Child] = 
List(Child(id = Some(1), parentId = 1, name = "John I"),
     Child(id = Some(2), parentId = 1, name = "John II"),
     Child(id = Some(3), parentId = 1, name = "John III"),
     Child(id = Some(4), parentId = 2, name = "Jake I"),
     Child(id = Some(5), parentId = 2, name = "Jake II"),
     Child(id = Some(5), parentId = 3, name = "Tamara I")
    )

我如何编写一个导致这种情况的函数?

List(
(Parent(Some(1),"John"), List(Child(id = Some(1), parentId = 1, name = "John I"),Child(id = Some(2), parentId = 1, name = "John II"),Child(id = Some(3), parentId = 1, name = "John III"))),
(Parent(Some(2),"Jake"), List(Child(id = Some(4), parentId = 2, name = "Jake I"),Child(id = Some(5), parentId = 2, name = "Jake II"))),
(Parent(Some(3),"Tamara")), List(Child(id = Some(5), parentId = 3, name = "Tamara I"))),
)

我已经有这个了:

  def groupParentChildren(parents : List[Parent], children : List[Child]) : List[(Parent, List[Child])] = {

children
  .groupBy(_.parentId)
  .map{case(parentId, children) => (parents.find(p => p.id.get == parentId), children)}
  .toList
  .flatMap{case(parentOpt, childrens) => parentOpt.map(parent => (parent, childrens))}
}

这似乎可以解决问题,但是在Scala中有没有更优雅的方法来实现结果?

1 个答案:

答案 0 :(得分:2)

最优雅的可能是:

parents.map {
  case p@Parent(Some(pid), _) => (p, children.filter(_.parentId == pid))
  case p => (p, Nil)
}

但这确实对children进行了许多不必要的扫描。效率更高一点:

val childrenByParentId = children.groupBy(_.parentId)
parents.map {
  case p@Parent(Some(pid), _) => (p, childrenByParentId.getOrElse(pid, Nil))
  case p => (p, Nil)
}