Simple way to filter a list based on future results of items in that list?

2,268 views
Skip to first unread message

Ryan LeCompte

unread,
Jul 10, 2013, 8:30:03 PM7/10/13
to akka...@googlegroups.com
Basically, if you have a method that returns a future, and you want to filter a list based on those futures (and the futures are built using values from the list), is there something simple that I can use out of the box? 

I came up with the following (example code, not actual code):

scala> val nums = 0 to 10
res17: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> def lookup(id: Int): Future[Option[Int]] = future { if (rnd.nextBoolean) Some(5) else None }
lookup: (id: Int)scala.concurrent.Future[Option[Int]]
 
scala> val collapsed = Future.sequence(nums.map { n => lookup(n).map { (n, _) } })
reduced: scala.concurrent.Future[scala.collection.immutable.IndexedSeq[(Int, Option[Int])]] = scala.concurrent.impl.Promise$DefaultPromise@5f0900d2
 
scala> val filtered = collapsed.map { results => results.collect { case (i, opt) if opt.isDefined => i } }
filtered: scala.concurrent.Future[scala.collection.immutable.IndexedSeq[Int]] = scala.concurrent.impl.Promise$DefaultPromise@7f5451cc
 

Ryan LeCompte

unread,
Jul 10, 2013, 8:32:56 PM7/10/13
to akka...@googlegroups.com
(I used a Future[Option[Int]] as the result from lookup(), but it's really some other Future[MyClass] that has an isEnabled method (I used isDefined on option to be similar in the example).

Som Snytt

unread,
Jul 10, 2013, 9:44:32 PM7/10/13
to akka...@googlegroups.com
Future.collect will effectively filter before you sequence; then, just flatten the bad results.

In your example, you filter with collect on the aggregate results.

The difference is that you could lookup(i).collect { case p => ... }.onSuccess(...)

object Test extends App {
  import util.{ Random => rnd, _ }
  import concurrent._
  import concurrent.duration._
  import ExecutionContext.Implicits.global


  val nums = 0 to 10
  def value(i: Int) = if (rnd.nextBoolean) Some(5) else None
  def lookup(id: Int) = future(value(id))
  def f(i: Int) = lookup(i) map ((i, _)) collect { case (i, Some(v)) => v }
  val all = nums map f
  val done = Future sequence all
  Await ready (done, Duration.Inf)
  val vs = all map (_.value.get.toOption)
  Console println vs.flatten
}






--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://akka.io/faq/
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ryan LeCompte

unread,
Jul 11, 2013, 9:29:49 AM7/11/13
to akka...@googlegroups.com
Nice alternative, I had forgotten about Future.collect. Thanks!
Reply all
Reply to author
Forward
0 new messages