在随后应用诸如map,flatmap等功能时,使用withFilter而不是filter总是表现更好吗?
为什么只支持map,flatmap和foreach?(预期功能如forall / exists)
Answers:
从Scala文档:
注:之间的区别
c filter p
,并c withFilter p
为前者创造一个新的集合,而后者只限制后续的域map
,flatMap
,foreach
,和withFilter
操作。
因此,filter
将采取原始集合和产生一个新的集合,但withFilter
将非严格(即懒洋洋地)到后来通过未过滤的值map
/ flatMap
/withFilter
调用,节省通过(过滤)收集第二遍。因此,当传递到这些后续方法调用时,它将更加高效。
实际上,withFilter
是专门为与这些方法的链一起使用而设计的,这对于理解方法是毫无用处的。不需要其他方法(例如forall
/ exists
),因此尚未将它们添加到的FilterMonadic
返回类型中withFilter
。
view
,如果你想映射/过滤器偷懒。
view
和之间的确切区别是withFilter
什么?为什么视图不用于for-loops
?
Don’t create temporary collections
在链接的部分中进行搜索。
withFilter
,Martin Odersky自己在Coursera的Scala课程中显式使用了它,我强烈建议这样做。考虑到他这样做,尽管差异通常只有1个字符,但这样做也可能给其他人带来安慰。例如seq.view filter p
对seq withFilter p
。
除了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起就是这种情况,因为理解力被翻译成
val result = list withFilter {
case i => go
} map {
case i => {
go = false
i
}
}
如您所见,翻译将条件转换为withFilter
。在Scala 2.8之前的版本中,对理解的理解如下:
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
的方法。
参考:-第120页,Scala的运用(涵盖Scala 2.10),Manning出版物,Milanjan Raychaudhuri- Odersky的理解翻译思想
未实现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)
请注意,ten_rand_even_naturals仍然是迭代器。只有当我们调用toList时,随机数才会生成并在链中进行过滤
请注意,map(identity)等同于map(i => i),在这里使用它是为了将withFilter对象转换回原始类型(例如,集合,流,迭代器)
使用yield可以解决,例如:
for {
e <- col;
if e isNotEmpty
} yield e.get(0)
解决方法是,可以仅使用map
和实现其他功能flatMap
。
而且,这种优化对小型馆藏毫无用处……