문제

Say I have been given a list of futures with each one linked to an key such as:

val seq: Seq[(Key, Future[Value])]

And my goal is to produce a list of key value tuples once all futures have completed:

val complete: Seq[(Key, Value)]

I am wondering if this can be achieved using a sequence call. For example I know I can do the following:

val complete = Future.sequence(seq.map(_._2).onComplete {
  case Success(s) => s
  case Failure(NonFatal(e)) => Seq()
}

But this will only returns me a sequence of Value objects and I lose the pairing information between Key and Value. The problem being that Future.sequence expects a sequence of Futures.

How could I augment this to maintain the key/value pairing in my complete sequence?

Thanks Des

도움이 되었습니까?

해결책

How about transforming your Seq[(Key, Future[Value])] to Seq[Future[(Key, Value)]] first.

val seq: Seq[(Key, Future[Value])] = // however your implementation is

val futurePair: Seq[Future[(Key, Value)]] = for {
    (key, value) <- seq
} yield value.map(v => (key, v))

Now you can use sequence to get Future[Seq[(Key, Value)]].

val complete: Future[Seq[(String, Int)]] = Future.sequence(futurePair)

다른 팁

Just a different expression of the other answer, using unzip and zip.

scala> val vs = Seq(("one",Future(1)),("two",Future(2)))
vs: Seq[(String, scala.concurrent.Future[Int])] = List((one,scala.concurrent.impl.Promise$DefaultPromise@4e38d975), (two,scala.concurrent.impl.Promise$DefaultPromise@35f8a9d3))

scala> val (ks, fs) = vs.unzip
ks: Seq[String] = List(one, two)
fs: Seq[scala.concurrent.Future[Int]] = List(scala.concurrent.impl.Promise$DefaultPromise@4e38d975, scala.concurrent.impl.Promise$DefaultPromise@35f8a9d3)

scala> val done = (Future sequence fs) map (ks zip _)
done: scala.concurrent.Future[Seq[(String, Int)]] = scala.concurrent.impl.Promise$DefaultPromise@56913163

scala> done.value
res0: Option[scala.util.Try[Seq[(String, Int)]]] = Some(Success(List((one,1), (two,2))))

or maybe save on zippage:

scala> val done = (Future sequence fs) map ((ks, _).zipped)
done: scala.concurrent.Future[scala.runtime.Tuple2Zipped[String,Seq[String],Int,Seq[Int]]] = scala.concurrent.impl.Promise$DefaultPromise@766a52f5

scala> done.value.get.get.toList
res1: List[(String, Int)] = List((one,1), (two,2))
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top