仍然会多次遍历集合的单行答案:
List(pred1, pred2, pred3).map(xs.filter)
作为方法:
def filterByFew(xs: List[Int], preds: List[Int => Boolean]): List[List[Int]] =
preds.map(xs.filter)
它以几乎相同的方式处理流:
val p1 = (x: Int) => x % 2 == 0
val p2 = (x: Int) => x % 3 == 0
val preds = List(p1, p2)
val str = Stream.from(0)
val filteredStreams = preds.map(str.filter)
filteredStreams foreach { s => println(s.take(10).toList) }
// Output:
// List(0, 2, 4, 6, 8, 10, 12, 14, 16, 18)
// List(0, 3, 6, 9, 12, 15, 18, 21, 24, 27)
但不要在 REPL 中尝试:REPL 会自行挂起为什么要显示中间结果。
遍历集合一次
如果您真的不能多次遍历集合,那么我看不到任何有效的解决方法,最简单的方法似乎是重新实现 filter,但使用多个可变构建器:
def filterByMultiple[A](
it: Iterator[A],
preds: List[A => Boolean]
): List[List[A]] = {
val n = preds.size
val predsArr = preds.toArray
val builders = Array.fill(n){
new collection.mutable.ListBuffer[A]
}
for (a <- it) {
for (j <- 0 until n) {
if (predsArr(j)(a)) {
builders(j) += a
}
}
}
builders.map(_.result)(collection.breakOut)
}
filterByMultiple((0 to 30).iterator, preds) foreach println
// Output:
// List(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30)
// List(0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30)
如果您是通过 Google 搜索来到这里的,那么您可能想要别的东西:
AND-ing 多个谓词:
def filterByAnd(xs: List[Int], preds: List[Int => Boolean]) =
xs.filter(x => preds.forall(p => p(x)))
OR-ing 多个谓词:
def filterByOr(xs: List[Int], preds: List[Int => Boolean]) =
xs.filter(x => preds.exists(p => p(x)))