CLEλR-C0DE

REVIEW How to execute sequentially a list of Futures

Simple code:

import scala.concurrent.{ExecutionContext, Future}

def sequentially[A, B](
    items: IterableOnce[A]
)(
    f: A => Future[B]
)(implicit
    ec: ExecutionContext
): Future[List[B]] =
  items.iterator.foldLeft(Future.successful(List.empty[B])) {
    (accFuture, item) =>
      for {
        acc <- accFuture
        processedItem <- f(item)
      } yield processedItem :: acc
  } map (_.reverse)

Keeps the container type the same as the argument:

import scala.collection.BuildFrom
import scala.concurrent.{ExecutionContext, Future}

def sequentially[A, B, M[X] <: IterableOnce[X]](
    items: M[A]
)(
    f: A => Future[B]
)(implicit
    bf: BuildFrom[M[A], B, M[B]],
    executor: ExecutionContext
): Future[M[B]] =
  items.iterator.foldLeft(Future.successful(List.empty[B])) {
    (accFuture, item) =>
      for {
        acc <- accFuture
        processedItem <- f(item)
      } yield processedItem :: acc
  } map (list => bf.newBuilder(items).addAll(list.reverse).result)

with parasitic:

import scala.collection.BuildFrom
import scala.concurrent.ExecutionContext.parasitic
import scala.concurrent.{ExecutionContext, Future}

def sequentially[A, B, M[X] <: IterableOnce[X]](
    items: M[A]
)(
    f: A => Future[B]
)(implicit
    bf: BuildFrom[M[A], B, M[B]],
    executor: ExecutionContext
): Future[M[B]] =
  items.iterator
    .foldLeft(Future.successful(List.empty[B]))((accFuture, item) =>
      for {
        acc <- accFuture
        processedItem <- f(item)
      } yield processedItem :: acc
    )
    .map(list => bf.newBuilder(items).addAll(list.reverse).result)(parasitic)