有没有更惯用的方法来简化 leftJoin 的结果?

Is there a more idiomatic way to simplify the results of a leftJoin?

我正在开发 Scala 2.12.x 和 Slick 3.3.0 项目,我有一个处理 joinLeft 操作结果的重复用例。

左连接给我这样的结果:Future[Seq[(A, Option[B])]] 其中 A 是主控类型 - table 和 B 是细节 -table 的类型。换句话说,我得到了主元素 A 的序列,重复了与 B 的左连接实例一样多的次数。我想将这种复杂的重复类型简化为更易于管理的结果类型 Future[Option[(A, Seq[B])]]。为此我创建了以下函数:

implicit def simplify[A, B](x: Future[Seq[(A, Option[B])]])(implicit ec: ExecutionContext): Future[Option[(A, Seq[B])]] = {
  x.map {
    case results => {
      val seq: Seq[B] = results.map(_._2).map {
        case Some(b) => Some(b)
        case _ => None.asInstanceOf[Option[B]]
      }.filterNot(_.isEmpty).map(_.get) match {
        case seq if (seq.nonEmpty) => seq
        case _ => Seq()
      }

      results.headOption.map {
        case (a, _) => (a, seq)
      }
    }
  }
}

但它看起来有点太复杂而且它没有说明可能有多个 A 实例的事实,例如

a1 b11
a1 b12
a1 b13
a2 b21
a2 b22

请注意,在这种情况下,我的函数会给出错误的结果:Future[Some((a1, Seq(b11, b12, b13, b21, b22)))],正确的结果是 Future[Some((a1, Seq(b11, b12, b13)))]

如何让它更简单更正确?

如果要将 A 值与定义的所有相应 B 值组合,可以使用 groupBy(_._1) 按元组的第一个元素分组,然后通过应用 mapValues(_.flatMap(_._2))

def simplify[A, B](x: Future[Seq[(A, Option[B])]])(implicit ec: ExecutionContext)
   : Future[Map[A, Seq[B]]] =
  x.map(_.groupBy(_._1).mapValues(_.flatMap(_._2)))

我将 return 类型更改为 Future[Map[A, Seq[B]]] 以允许不同的 A 值