I've been stuck and was wondering how I can convert Map[A, Seq[Future[Option[B]]]]
to Future[Map[A, Seq[B]]]
?
Simplest way would be something like:
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)
}
What you had before edition of your question ( Map[A, Future[Option[B]]
) would be handled simpler way with cats if you had 2 things defined
// 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] = ...
then you could do it simply with:
// assuming traverse syntax imported
val futureMap: Future[Map[A, Option[B]] = yourMap.sequence
the data in your current form, however, forces us to do it in a hard way.
This version avoid re-grouping the data by converting the Map
to List
and then back again.
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)
The inner map
uses Future.sequence
to convert each entry from A -> Seq[Future[Option[B]]]
to Future[A -> Seq[B]]
.
The outer Future.sequence
converts the List[Future[A -> Seq[B]]]
to Future[List[A -> Seq[B]]]
.
The outer map
converts this List
back to a Map
.
This compiles so the types are right, but I have not tested it on any real data
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.