29

私は Scala Akka ライブラリを使用していて、ちょっとした問題に遭遇しました。タイトルが示すように、私はに変換する必要がありMap[A, Future[B]]ますFuture[Map[A,B]]Future.sequenceリストのようなイテラブルに使用できることは知っていますが、この場合は機能しません。

私は疑問に思っていました.Scalaでこの変換を行うためのきれいな方法はありますか?

4

7 に答える 7

30

これがうまくいくかどうかを確認してください:

val map = Map("a" -> future{1}, "b" -> future{2}, "c" -> future{3})    
val fut = Future.sequence(map.map(entry => entry._2.map(i => (entry._1, i)))).map(_.toMap)

アイデアは、マップのキーのIterablefor にマップをマップしTuple、そのキーに関連付けられた未来の結果をマップすることです。そこからそれができsequenceIterable集約を取得したら、それをマップし、それを経由でマップにFuture変換します。 IterableTuplestoMap

さて、このアプローチに代わる方法は、sequence関数が行っていることと似たようなことを試してみることです。sequenceMap次のような関数を書くことができます:

def sequenceMap[A, B](in: Map[B, Future[A]])(implicit executor: ExecutionContext): Future[Map[B, A]] = {
  val mb = new MapBuilder[B,A, Map[B,A]](Map())
  in.foldLeft(Promise.successful(mb).future) {
    (fr, fa) => for (r <- fr; a <- fa._2.asInstanceOf[Future[A]]) yield (r += ((fa._1, a)))
  } map (_.result)
}

そして、次のような例で使用します。

val map = Map("a" -> future{1}, "b" -> future{2}, "c" -> future{3})    
val fut = sequenceMap(map)
fut onComplete{
  case Success(m) => println(m)
  case Failure(ex) => ex.printStackTrace()
}

これは、作成される中間コレクションが少なくなり、ExecutionContext.

于 2013-07-04T23:58:33.033 に答える
13

コア Scala 2.12.x でできる最も簡潔なことは、

val futureMap = Map("a" -> future{1}, "b" -> future{2}, "c" -> future{3}) 

Future.traverse(futureMap.toList) { case (k, fv) => fv.map(k -> _) } map(_.toMap)
于 2014-08-27T01:13:26.070 に答える
4

これは、(マップの値の) シーケンス結果を使用して、マップから値の取得を開始できるという promise を起動するというアイデアでも機能します。 mapValuesマップの非厳密なビューを提供するためvalue.get.get、値を取得するときにのみ適用されます。そうです、あなたはあなたの地図を保つことができます!そのリンクの謎解きの無料広告。

import concurrent._
import concurrent.duration._
import scala.util._
import ExecutionContext.Implicits.global

object Test extends App {
  def calc(i: Int) = { Thread sleep i * 1000L ; i }
  val m = Map("a" -> future{calc(1)}, "b" -> future{calc(2)}, "c" -> future{calc(3)})
  val m2 = m mapValues (_.value.get.get)
  val k = Future sequence m.values
  val p = Promise[Map[String,Int]]
  k onFailure { case t: Throwable => p failure t }
  k onSuccess { case _ => p success m2 }
  val res = Await.result(p.future, Duration.Inf) 
  Console println res
}

これは、すべての値を出力して m2 マップを強制する REPL です。

scala> val m2 = m mapValues (_.value.get.get)
m2: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2, c -> 3)

これは、まだ未来にある先物と同じことを示しています。

scala>   val m2 = m mapValues (_.value.get.get)
java.util.NoSuchElementException: None.get
于 2013-07-05T00:52:10.247 に答える
1

マップ値のすべての先物を待つ新しい未来を作成し、マップを構築して返すだけです。

于 2013-07-04T23:53:57.460 に答える