1

I am trying to fix the following issue:

I have a Future[Map[A, B]]. For all B, I need to apply a method that convert B to a Future[C] and I want to give back a Future[Map[A, C]]

Here is the code I have so far:

def getClients(clientIds: Seq[Int]): Future[Map[Int, ClientData]] = {

  def getClientData(clientInfo: ClientInfo): Future[ClientData] = 
    clientInfo match {
      case ValidInfo(info) => getData(info)
      case _ => throw new Exception
    }

  client.getClients(clientIds) map {
    _.toMap map {
      case (clientId: Int, clientInfo: ClientInfo) =>
        getClientData(clientInfo) map {
          clientData => (clientId, clientData)
      }
    }
  }
}

This code is wrong as it returns a Iterable[Future[(Int, ClientData)]]

For info getClients is a thrift method that returns Future[Map[A, B]] where the Map is mutable, so I need to convert it to an immutable map first with toMap.

Thank you in advance for your help!

snessarb
  • 85
  • 1
  • 1
  • 6

1 Answers1

7
scala> def f: Future[Map[String, Future[Int]]] = ???
f: Future[Map[String,Future[Int]]]

scala> def x = for {
     |   m <- f
     |   i = m.map{ case (k, fv) => fv.map{ k -> _ } }
     |   l <- Future.sequence(i)
     | } yield l.toMap
x: Future[Map[String,Int]]

Step by step:

Convert Future[Map[A, Future[B]]] to Future[Iterable[Future[(A, B)]]]:

scala> def x1 = f.map{ _.map{ case (k, fv) => fv.map{ k -> _ } } }
x1: Future[Iterable[Future[(String, Int)]]]

Convert Iterable[Future[(A, B)]] to Future[Iterable[(A, B)]] and flatten Future[Future[...]] using flatMap:

scala> def x2 = x1.flatMap{ Future.sequence(_) }
x2: Future[immutable.Iterable[(String, Int)]]

Convert Iterable[(A, B)] to Map[A, B]:

scala> def x = x2.map{ _.toMap }
x: Future[Map[String,Int]]

For com.twitter.util.Future you should use collect instead of sequence and toSeq before collect since it accepts Seq:

def x = for {
  m <- f
  i = m.map{ case (k, fv) => fv.map{ k -> _ } }
  l <- Future.collect(i.toSeq)
} yield l.toMap
senia
  • 37,745
  • 4
  • 88
  • 129
  • Thanks a lot for your fast response! But there is no Future.sequence in Finagle! There is a Future.collect but it does not seems to work here ... – snessarb Dec 03 '13 at 20:45
  • @user3063038: what is your scala version? [Here is `sequence` method](https://github.com/scala/scala/blob/v2.10.3/src/library/scala/concurrent/Future.scala#L487) in 2.10.3. – senia Dec 03 '13 at 20:48
  • I am using 2.10.3 but a com.twitter.util.Future which apparently has no sequence method : http://twitter.github.io/util/util-core/target/doc/main/api/com/twitter/util/Future.html – snessarb Dec 03 '13 at 20:52
  • @user3063038: see update. `collect` should works just fine (after `toSeq`). – senia Dec 03 '13 at 20:55
  • Yes! I tried it in the meantime as well and it worked! Thanks a lot! – snessarb Dec 03 '13 at 21:02