Scala 按未来结果筛选集合

Scala filter collection by future result

我有一个名为 Source 的 class,它有惰性 val isValid,它会做一些需要时间的网络检查。我已经做到 return Future[Boolean] 所以它不会阻塞主线程:

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

现在,我想检查一些 来源 并丢弃无效的。
这是一些伪代码:

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

我在想一些方法,可以将 Future[Boolean] returned 从 isValid 转换为其他 Future ,可以用整个 验证检查完成后的 Source 对象。

最好的方法是什么?

无需 return 来自 isValidSource 本身。只需将源本身附加到 isValid 请求的每个结果。 一旦有效性检查的结果存在,过滤那些来源 有效,并丢弃有效性布尔值:

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))

在这里,s.isValidreturn是Future[Boolean]。这个未来是用 b => (s, b) 映射的,因此 s.isValid.map(b => (s, b))Future[(Source, Boolean)]Future.sequence 将一堆未来转化为序列的单一未来。一旦序列被计算出来,它可以被第二个组件过滤,然后第二个组件可以被丢弃。

我不确定这是否是执行此操作的“最佳”方法,因为我不清楚有效性检查在多长时间内保持足够“新鲜”:很可能是[的一半结果=13=] 到所有结果都收集到 checkedSources 序列时检查已过时。


编辑 (1): 更短:

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

这应该也有效。

(未经编译器检查的代码,我头脑中的粗略草图;如果您想要一个可编译的解决方案,请提供最小的可编译示例)