用过滤器代替过滤器

使用 Filter 代替 filter 是否总是更加有效,当之后应用诸如 map、 latmap 等函数时。?

为什么只支持 map、 latmap 和 foreach

23110 次浏览

作为解决方案,您可以只使用 mapflatMap实现其他函数。

此外,这种优化对于小型收藏品毫无用处... ..。

用于获得收益可以是一种解决办法,例如:

for {
e <- col;
if e isNotEmpty
} yield e.get(0)

来自 Scala 文档:

注意: c filter pc withFilter p的区别在于前者 创建一个新集合,而后者仅限制 随后的 mapflatMapforeachwithFilter操作。

因此,filter将获取原始集合并生成一个新集合,但是 withFilter将非严格地(即懒惰地)将未过滤的值传递给以后的 map/flatMap/withFilter调用,从而保存通过(过滤的)集合的第二次传递。因此,当传递到这些后续方法调用时,它将更有效率。

事实上,withFilter是专门为处理这些方法的链而设计的,这就是 for 理解被去糖化的原因。这不需要其他方法(如 forall/exists) ,因此它们没有被添加到 withFilterFilterMonadic返回类型中。

除了 Shadowlands 的绝妙回答,我想带来一个直观的例子之间的差异 filterwithFilter

让我们考虑以下代码

val list = List(1, 2, 3)
var go = true
val result = for(i <- list; if(go)) yield {
go = false
i
}

大多数人认为 result等于 List(1)。这是自 Scala 2.8以来的情况,因为 for 理解被翻译成

val result = list withFilter {
case i => go
} map {
case i => {
go = false
i
}
}

正如您所看到的,转换将条件转换为对 withFilter的调用。在 Scala 2.8之前,for-understand 被翻译成如下内容:

val r2 = list filter {
case i => go
} map {
case i => {
go = false
i
}
}

使用 filter时,result的值会有很大的不同: List(1, 2, 3)。事实上,我们正在使 go标志 false对过滤器没有影响,因为过滤器已经完成了。同样,在 Scala 2.8中,这个问题是使用 withFilter解决的。当使用 withFilter时,每次在 map方法内访问元素时都会计算条件。

参考 : - p. 120,Scala in action (涵盖 Scala 2.10) ,曼宁出版社,Milanjan Raychaudhuri 奥德斯基关于理解翻译的思想

就一切[存在]而言没有实现的主要原因是用例是:

  • 您可以懒惰地将 withFilter 应用于无限流/迭代
  • 你可以懒惰地使用 Filter (一次又一次)应用另一个

为了实现 就一切[存在]而言,我们需要获得所有的元素,摆脱懒惰。

例如:

import scala.collection.AbstractIterator


class RandomIntIterator extends AbstractIterator[Int] {
val rand = new java.util.Random
def next: Int = rand.nextInt()
def hasNext: Boolean = true
}


//rand_integers  is an infinite random integers iterator
val rand_integers = new RandomIntIterator


val rand_naturals =
rand_integers.withFilter(_ > 0)


val rand_even_naturals =
rand_naturals.withFilter(_ % 2 == 0)


println(rand_even_naturals.map(identity).take(10).toList)


//calling a second time we get
//another ten-tuple of random even naturals
println(rand_even_naturals.map(identity).take(10).toList)

请注意,十兰特甚至天然的仍然是一个迭代器。当我们调用 列表时,随机数将被生成并在链中过滤

请注意,地图(身分)等价于 地图(i = > i),这里使用它是为了将 withFilter 对象转换回原始类型(例如集合、流、迭代器)

关于全部/存在的部分:

someList.filter(conditionA).forall(conditionB)

将是相同的(虽然有点不直观)

!someList.exists(conditionA && !conditionB)

类似地,. filter () . vis ()可以组合成一个 vis ()检查吗?