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

时间:2019-06-03 20:55:32

标签: scala slick

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

左联接为我提供了以下结果:Future[Seq[(A, Option[B])]],其中A是主表的类型,B是明细表的类型。换句话说,我得到了一个主元素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)))]

如何使它更简单和正确?

1 个答案:

答案 0 :(得分:2)

如果要将A值与定义的所有对应B值组合在一起,则可以使用groupBy(_._1)按元组的第一个元素分组,然后通过应用{{1}来展平B选项}

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))) 以允许使用不同的A值