Scala filter collection by future result
Asked Answered
C

1

7

I have a class called Source, it has lazy val isValid which does some network checks that takes time. I've made it to return Future[Boolean] so it won't block main thread:

lazy val isValid: Future[Boolean] = doSomeChecks()

Now, I want to check few Sources and discard invalid ones.
Here's some pseudo code:

val sources = Seq(Source1, Source2,...)
val validOnes: Seq[Source] = sources.filter(_.isValid)

I was thinking of some method that would transform Future[Boolean] returned from isValid into some other Future that would resolve with whole Source object after validation checks finish.

What is the best way to do this?

Clausen answered 3/2, 2018 at 22:34 Comment(0)
T
7

No need to return the Source itself from isValid. Simply append the source itself to each result of an isValid request. Once the results of validity checks are there, filter those sources that are valid, and throw away the validity-boolean:

val sources: Seq[Source] = ...

val validSources: Future[Seq[Source]] = (for {
  checkedSources <- Future.sequence(
    sources.map(s => s.isValid.map(b => (s, b)))
  )
} yield checkedSources.filter(_._2).map(_._1))

Here, s.isValid returns a Future[Boolean]. This future is mapped with b => (s, b), so that s.isValid.map(b => (s, b)) is a Future[(Source, Boolean)]. The Future.sequence transforms bunch of futures into a single future of a sequence. Once the sequence has been computed, it can be filtered by the second component, and then the second component can be discarded.

I'm not sure whether this is "the best" way to do this, because it's not clear to me how long the validity check remains sufficiently "fresh": it might well be that half of the results of isValid checks are outdated by the time all results are collected into the checkedSources sequence.


EDIT (1): Even shorter:

val validSources: Future[Seq[Source]] = 
  Future.sequence(sources.map(_.isValid)).map {
    bs => (sources zip bs).filter(_._2).map(_._1)
  }

This should work too.

(code unchecked with compiler, rough sketch off the top of my head; Please provide minimal compilable example if you want a compilable solution)

Tenement answered 3/2, 2018 at 22:58 Comment(1)
Thanks, just wanted an idea, no need to provide working code. I was just wondering if there is some cleaner way than zipping it together into tuples.Clausen

© 2022 - 2024 — McMap. All rights reserved.