Chr*_*imm 29 scala future akka
我一直在使用Scala Akka库并遇到了一些问题.正如标题所说,我需要转换Map[A, Future[B]]为Future[Map[A,B]].我知道可以使用Future.sequence像Lists这样的Iterables,但在这种情况下这不起作用.
我想知道:在Scala中有一个干净的方法来进行这种转换吗?
cmb*_*ter 27
看看这是否适合您:
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)
Run Code Online (Sandbox Code Playgroud)
我们的想法是将地图映射到地图的Iterable一个Tuple关键字以及与该关键字相关的未来结果.从那里,你可以sequence说Iterable,然后,一旦你有聚集Future,它映射和转换是Iterable的Tuples通过一个地图toMap.
现在,这种方法的另一种方法是尝试做一些类似于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)
}
Run Code Online (Sandbox Code Playgroud)
然后在这样的示例中使用它:
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()
}
Run Code Online (Sandbox Code Playgroud)
这可能比第一个示例稍微有效,因为它创建的中间集合较少,而且点击次数较少ExecutionContext.
Jof*_*fer 12
我认为Scala核心最简洁的是
val map = Map("a" -> future{1}, "b" -> future{2}, "c" -> future{3})
Future.traverse(map) { case (k, fv) => fv.map(k -> _) } map(_.toMap)
Run Code Online (Sandbox Code Playgroud)
更新:你可以.sequence在Scalaz 7中实际获得漂亮的语法,而不用太大惊小怪:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{ Future, future }
import scalaz._, Scalaz.{ ToTraverseOps => _, _ }
import scalaz.contrib.std._
val m = Map("a" -> future(1), "b" -> future(2), "c" -> future(3))
Run Code Online (Sandbox Code Playgroud)
然后:
scala> m.sequence.onSuccess { case result => println(result) }
Map(a -> 1, b -> 2, c -> 3)
Run Code Online (Sandbox Code Playgroud)
原则上,没有必要ToTraverseOps像这样隐藏,但是现在它可以解决问题.有关Traverse类型类,依赖项等的更多详细信息,请参阅下面的其余答案.
正如上面评论中的copumpkin注释,Scalaz包含一个带有实例的Traverse类型类,Map[A, _]这是其中一个拼图.另一个是Applicative实例Future,它不在Scalaz 7中(它仍然是针对Future2.9 之前的交叉构建),但是在scalaz-contrib.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scalaz._, Scalaz._
import scalaz.contrib.std._
def sequence[A, B](m: Map[A, Future[B]]): Future[Map[A, B]] = {
type M[X] = Map[A, X]
(m: M[Future[B]]).sequence
}
Run Code Online (Sandbox Code Playgroud)
要么:
def sequence[A, B](m: Map[A, Future[B]]): Future[Map[A, B]] =
Traverse[({ type L[X] = Map[A, X] })#L] sequence m
Run Code Online (Sandbox Code Playgroud)
要么:
def sequence[A, B](m: Map[A, Future[B]]): Future[Map[A, B]] =
TraverseOpsUnapply(m).sequence
Run Code Online (Sandbox Code Playgroud)
在一个完美的世界中,你可以编写m.sequence,但TraverseOps应该使这种语法成为可能的机制目前无法告诉如何从特定Map实例转到适当的Traverse实例.