同时处理重复项的序列

Mic*_*ael 2 collections concurrency scala future

假设我有一个function fab: A => B,一个序列,A并且需要得到一个(A, B)像这样的成对序列:

def foo(fab: A => B, as: Seq[A]): Seq[(A, B)] = as.zip(as.map(fab))
Run Code Online (Sandbox Code Playgroud)

现在,我想运行fab同时使用scala.concurrent.Future,但我想运行fab一次在所有重复的元素as。例如,

val fab: A => B = ...
val a1: A = ...
val a2: A = ...
val as = a1 :: a1 :: a2 :: a1 :: a2 :: Nil
foo(fab, as) // invokes fab twice and run these invocations concurrently
Run Code Online (Sandbox Code Playgroud)

您将如何实施?

And*_*kin 5

def foo[A, B](as: Seq[A])(f: A => B)(implicit exc: ExecutionContext)
: Future[Seq[(A, B)]] = {
  Future
    .traverse(as.toSet)(a => Future((a, (a, f(a)))))
    .map(abs => as map abs.toMap)
}
Run Code Online (Sandbox Code Playgroud)

说明:

  1. as.toSet确保f每个对象仅被调用一次a
  2. (a, (a, f(a)))为您提供了一组与形状的元组嵌套(a, (a, b))
  3. as 的原始序列映射为Map带有对的,即可(a, (a, b))得到(a, b)s 序列。

由于您f仍然不是异步的,并且由于您不介意使用期货,因此您也可以考虑使用par-collections:

def foo2[A, B](as: Seq[A])(f: A => B): Seq[(A, B)] = {
  as map as.toSet.par.map((a: A) => a -> (a, f(a))).seq.toMap
}
Run Code Online (Sandbox Code Playgroud)