Scala 将 Map[A, Seq[Future[Option[B]]]] 转换为 Future[Map[A, Seq[B]]]?

Scala convert Map[A, Seq[Future[Option[B]]]] to Future[Map[A, Seq[B]]]?

我被卡住了,想知道如何将 Map[A, Seq[Future[Option[B]]]] 转换为 Future[Map[A, Seq[B]]]

最简单的方法是:

val yourMap: Map[A, Seq[Future[Option[B]]]] = ...

val flattenedValues: Map[A, Future[Seq[B]]] = yourMap.mapValues { seqFuture =>
  Future.sequence(seqFuture).map(seqOpt => seqOpt.flatten)
}

val seqOfFutures: Seq[Future[(A, Seq[B])]] = flattenedValues.toSeq.map {
  case (a, futureSeqB) =>
    future.map(optionB => a -> optionB)
}

val futureOfSeq: Future[Seq[(A, Seq[B])]] = Future.sequence(seqOfFutures)

val result: Future[Map[A, Seq[B]]] = futureOfSeq.map { seq =>
  seq.groupBy(_._1).mapValues(_.map(_._2).flatten)
}

如果你定义了 2 个东西,你在问题版本 (Map[A, Future[Option[B]]) 之前的内容将以更简单的方式处理猫

// as far as I can tell defined only in Alleycats
implicit def traverseMap[A]: cats.Traverse[Map[A, *]] = ...
// as far as I can tell defined in Cats
implicit def applicativeFuture: cats.Applicative[Future] = ...

那么你可以简单地做到这一点:

// assuming traverse syntax imported
val futureMap: Future[Map[A, Option[B]] = yourMap.sequence

然而,您当前表格中的数据迫使我们以艰难的方式进行。

此版本通过将 Map 转换为 List 然后再返回来避免重新分组数据。

val in: Map[A, Seq[Future[Option[B]]]] = ???

val out: Future[Map[A, Seq[B]]] =
  Future.sequence(
    in.toList.map {
      case (k, v) => Future.sequence(v).map(k -> _.flatten)
    }
  ).map(_.toMap)

内部map使用Future.sequence将每个条目从A -> Seq[Future[Option[B]]]转换为Future[A -> Seq[B]]

外部Future.sequenceList[Future[A -> Seq[B]]]转换为Future[List[A -> Seq[B]]]

外部 map 将此 List 转换回 Map

这个编译所以类型是正确的,但我没有在任何真实数据上测试它