在应用map,flatmap等函数时,始终使用withFilter比filter更高效吗?
为什么只支持map、 flatmap和foreach?(期望像forall / exists这样的函数也被支持)
在应用map,flatmap等函数时,始终使用withFilter比filter更高效吗?
为什么只支持map、 flatmap和foreach?(期望像forall / exists这样的函数也被支持)
来自Scala文档:
注意:
c filter p
和c withFilter p
的区别在于前者会创建一个新的集合,而后者仅限制后续map
、flatMap
、foreach
和withFilter
操作的域。
因此,filter
将使用原始集合生成一个新集合,但withFilter
将非严格(即惰性地)传递未经过滤的值到以后的map
/flatMap
/withFilter
调用中,从而节省对(过滤后的)集合的第二次遍历。因此,当传递到这些后续方法调用时,它将更有效率。
withFilter
是专门为处理这些方法链设计的,这也是 for 推导式被解糖成的形式。没有其他方法(如 forall
/exists
)需要使用,因此它们没有被添加到 withFilter
的 FilterMonadic
返回类型中。view
。 - Luigi Plingeview
和 withFilter
之间的确切区别是什么?为什么不将 view
用于 for-loops
? - KigyowithFilter
,Martin Odersky本人在Coursera的Scala课程中明确地使用了它,我强烈推荐这个课程。鉴于他这么做了,可能会让其他人也更愿意这样做,尽管区别通常只有一个字符。例如,seq.view filter p
与seq withFilter p
。 - Chuck Daniels除了Shadowlands的精彩回答之外,我想带来一个直观的例子,来说明filter
和withFilter
之间的区别。
让我们考虑下面的代码:
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推导式被翻译成了
Most people expect result
to be equal to List(1)
. This is the case since Scala 2.8, because the for-comprehension is translated into
val result = list withFilter {
case i => go
} map {
case i => {
go = false
i
}
}
正如您所看到的,该翻译将条件转换为对withFilter
的调用。在Scala 2.8之前,for循环推导式会被翻译成以下内容:
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),Manning Publications,Milanjan Raychaudhuri - Odersky关于for-comprehension翻译的思考
forall/exists没有被实现的主要原因是:
为了实现forall/exists,我们需要获取所有元素,失去了惰性。
例如:
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)
someList.filter(conditionA).forall(conditionB)
这个内容的意思是相同的,尽管有些不太直观。
!someList.exists(conditionA && !conditionB)
使用yield可以是一种解决方法,例如:
for {
e <- col;
if e isNotEmpty
} yield e.get(0)
作为一种解决方法,您可以仅使用map
和flatMap
实现其他功能。
此外,在小集合上进行此优化是无用的...