在使用map,flatmap等函数后,使用withFilter而不是过滤器总是更高效吗?
为什么只支持map,flatmap和foreach? (预期的功能,如forall /存在)
答案 0 :(得分:111)
注意:
c filter p
和c withFilter p
之间的区别在于前者 创建一个新的集合,而后者只限制域的 后续的map
,flatMap
,foreach
和withFilter
操作。
因此filter
会获取原始集合并生成新集合,但withFilter
会非严格(即懒惰地)将未经过滤的值传递给后来的map
/ {{1} } / flatMap
调用,保存第二遍(过滤)集合。因此,当传递给这些后续方法调用时,它会更有效。
事实上,withFilter
是专门为处理这些方法的链而设计的,这是理解被去除的。此处不需要其他方法(例如withFilter
/ forall
),因此它们尚未添加到exists
的{{1}}返回类型中。
答案 1 :(得分:7)
除the excellent answer of 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-comprehension被翻译成
val result = list withFilter {
case i => go
} map {
case i => {
go = false
i
}
}
正如您所看到的,翻译会将条件转换为对withFilter
的调用。之前的Scala 2.8,for-comprehension被翻译成如下内容:
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 Publications,Milanjan Raychaudhuri - Odersky's thoughts about for-comprehension translation
答案 2 :(得分:1)
对于永远存在的部分:
someList.filter(conditionA).forall(conditionB)
将与(虽然有点不直观)相同
!someList.exists(conditionA && !conditionB)
类似地,.filter()。exists()可以合并为一个exist()检查吗?
答案 3 :(得分:0)
因为 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)
请注意, ten_rand_even_naturals 仍然是迭代器。 仅当我们调用 toList 时,将生成随机数并在链中进行过滤
请注意, map(identity)等同于 map(i =&gt; i),此处使用它来将withFilter对象转换回原始对象类型(例如集合,流,迭代器)
答案 4 :(得分:-3)
用于收益可以是一种解决方法,例如:
for {
e <- col;
if e isNotEmpty
} yield e.get(0)
答案 5 :(得分:-5)
作为一种变通方法,您只能使用map
和flatMap
来实现其他功能。
此外,这种优化对小型集合来说毫无用处......