scala 用过滤器代替过滤器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19617378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:47:53  来源:igfitidea点击:

withFilter instead of filter

scalalazy-evaluationscala-collectionsfor-comprehension

提问by Kigyo

Is it always more performant to use withFilter instead of filter, when afterwards applying functions like map, flatmap etc.?

在之后应用 map、flatmap 等函数时,使用 withFilter 而不是 filter 总是更高效吗?

Why are only map, flatmap and foreach supported? (Expected functions like forall/exists as well)

为什么只支持 map、flatmap 和 foreach?(预期的功能,如 forall/exists 也是如此)

回答by Shadowlands

From Boolean):scala.collection.generic.FilterMonadic[A,Repr]" rel="noreferrer">the Scala docs:

来自Boolean):scala.collection.generic.FilterMonadic[A,Repr]" rel="noreferrer">Scala 文档

Note: the difference between c filter pand c withFilter pis that the former creates a new collection, whereas the latter only restricts the domain of subsequent map, flatMap, foreach, and withFilteroperations.

注:之间的区别c filter p,并c withFilter p为前者创造一个新的集合,而后者只限制后续的域mapflatMapforeach,和withFilter操作。

So filterwill take the original collection and produce a new collection, but withFilterwill non-strictly (i.e. lazily) pass unfiltered values through to later map/flatMap/withFiltercalls, saving a second pass through the (filtered) collection. Hence it will be more efficient when passing through to these subsequent method calls.

因此,filter将采取原始集合和产生一个新的集合,但withFilter将非严格(即懒洋洋地)到后来通过未过滤的值map/ flatMap/withFilter调用,节省通过(过滤)收集第二遍。因此,在传递到这些后续方法调用时会更有效。

In fact, withFilteris specifically designed for working with chains of these methods, which is what a for comprehension is de-sugared into. No other methods (such as forall/exists) are required for this, so they have not been added to the FilterMonadicreturn type of withFilter.

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

回答by ZenLulz

In addition of the excellent answer of Shadowlands, I would like to bring an intuitive example of the difference between filterand withFilter.

除了Shadowlands的优秀回答,我想带一个直观的例子来说明filterwithFilter

Let's consider the following code

让我们考虑以下代码

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

Most people expect resultto be equal to List(1). This is the case since Scala 2.8, because the for-comprehension is translated into

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

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

As you can see the translation converts the condition into a call to withFilter. Prior Scala 2.8, for-comprehension were translated into something like the following:

如您所见,翻译将条件转换为对withFilter. 在 Scala 2.8 之前,for-comprehension 被翻译成如下内容:

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

Using filter, the value of resultwould be fairly different: List(1, 2, 3). The fact that we're making the goflag falsehas no effect on the filter, because the filter is already done. Again, in Scala 2.8, this issue is solved using withFilter. When withFilteris used, the condition is evaluated every time an element is accessed inside a mapmethod.

使用filter, 的值result会大不相同:List(1, 2, 3)。我们制作go标志这一事实false对过滤器没有影响,因为过滤器已经完成。同样,在 Scala 2.8 中,使用withFilter. 当withFilter被使用时,条件被评估每一个元件被一个内部访问的时间map的方法。

Reference: - p.120 ,Scala in action (covers Scala 2.10), Manning Publications, Milanjan Raychaudhuri - Odersky's thoughts about for-comprehension translation

参考: - p.120,Scala in action(涵盖 Scala 2.10),Manning Publications,Milanjan Raychaudhuri - Odersky 关于理解翻译的想法

回答by frhack

The main reason because forall/existsaren't implemented is that the use case is that:

因为forall/exists没有实现的主要原因是用例是:

  • you can lazily apply withFilter to an infinite stream/iterable
  • you can lazily apply another withFilter (and again and again)
  • 您可以懒惰地将 withFilter 应用于无限流/可迭代
  • 你可以懒惰地应用另一个 withFilter(一次又一次)

To implement forall/existswe need to obtain all the elements, loosing the lazyness.

要实现forall/exists,我们需要获取所有元素,从而消除惰性。

So for example:

例如:

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)

Note that ten_rand_even_naturalsis still an iterator. Onlywhen we call toListthe random numbers will be generated and filtered in chain

请注意,ten_rand_even_naturals仍然是一个迭代器。只有当我们调用toList 时,才会在链中生成和过滤随机数

Note that map(identity)is equivalent to map(i=>i)and it is used here in order to convert a withFilter object back to the original type (eg a collection , a stream, an iterator)

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

回答by lznt

For the forall/exists part:

对于 forall/exists 部分:

someList.filter(conditionA).forall(conditionB)

would be the same as (though a little bit un-intuitive)

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

!someList.exists(conditionA && !conditionB)

Similarly, .filter().exists() can be combined into one exists() check?

类似地, .filter().exists() 可以合并为一个 exists() 检查吗?

回答by facebook-100001836197736

Using for yield can be a work around, for example:

使用 for yield 可以解决,例如:

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

回答by Yann Moisan

As a workaround, you can implement other functions with only mapand flatMap.

作为一种解决方法,您可以仅使用map和来实现其他功能flatMap

Moreover, this optimisation is useless on small collections…

而且,这种优化在小集合上是无用的……