withFilter代替filter


Answers:


121

Scala文档

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

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

实际上,withFilter是专门为与这些方法的链一起使用而设计的,这对于理解方法是毫无用处的。不需要其他方法(例如forall/ exists),因此尚未将它们添加到的FilterMonadic返回类型中withFilter


希望他们有一天会继续添加这些方法。
Kigyo,2013年

1
@Kigyo我认为您不应该自己使用withFilter(除了隐含在for表达式中)。使用view,如果你想映射/过滤器偷懒。
路易吉·普林格

我懂了。view和之间的确切区别是withFilter什么?为什么视图不用于for-loops
Kigyo 2013年

5
仅供参考,我认为“收藏集-技巧和窍门”提供了出色的信息。H5不是固定锚,但是您可以Don’t create temporary collections在链接的部分中进行搜索。
sthzg '16

4
关于显式使用withFilter,Martin Odersky自己在Coursera的Scala课程中显式使用了它,我强烈建议这样做。考虑到他这样做,尽管差异通常只有1个字符,但这样做也可能给其他人带来安慰。例如seq.view filter pseq withFilter p
Chuck Daniels

9

除了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的理解翻译思想


1

未实现forall / exists的主要原因是该用例是:

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

要实现永久/存在,我们需要获得所有要素,从而消除惰性。

因此,例如:

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对象转换回原始类型(例如,集合,流,迭代器)


1

对于永久/存在部分:

someList.filter(conditionA).forall(conditionB)

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

!someList.exists(conditionA && !conditionB)

同样,.filter()。exists()可以合并为一个exist()检查吗?



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.