scala - 如何一次通过多个谓词过滤列表?

标签 scala collections

假设我通过几个谓词过滤列表,例如

val xs = List(1, 0, -1, 2, 3, 4, 5, -6, 5, 0)
val pred1: Int => Boolean = _ > 0
val pred2: Int => Boolean = _ < 0
val pred3: Int => Boolean = _ % 2 == 0

val xs1 = xs.filter(pred1) // List(1, 2, 3, 4, 5, 5)
val xs2 = xs.filter(pred2) // List(-1, -6)
val xs3 = xs.filter(pred3) // List(0, 2, 4, -6, 0)

如何一次通过所有这些谓词过滤列表?

def filterByFew(xs: List[Int], preds: List[Int => Boolean]): List[List[Int]] = ???

filterByFew(xs, List(pred1, pred2, pred3)) 应该返回
列表(列表(1, 2, 3, 4, 5, 5), 列表(-1, -6), 列表(0, 2, 4, -6, 0))

最佳答案

仍然多次遍历集合的一行答案:

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 多个谓词:

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

关于scala - 如何一次通过多个谓词过滤列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53652520/

相关文章:

java - 带扫描仪的 ArrayList 无法正常工作

java - ArrayList 通过 Id 检索对象

java - scala InputStreamReader 不读取整个数据(文件)

scala - 如何从 Scala 中的 Future 返回不同的结果而不以嵌套 if 语句结束

events - Scala 中的惯用事件引擎

magento - 仅选择Magento中的特定字段

scala - 将 Scala 应用程序作为 Java 应用程序运行

scala - Play 2.5 akka.stream.Materializer 有什么用?

java - Vaadin:创建 TabSheets 的 ArrayList

c# - 将 IList 转换为集合