web-dev-qa-db-ja.com

フィルターの代わりにwithFilter

後でmap、flatmapなどの関数を適用するときに、filterではなくwithFilterを使用する方が常にパフォーマンスが向上しますか?

Map、flatmap、foreachのみがサポートされているのはなぜですか? (forall/existsなどの期待される機能)

76
Kigyo

から the Scala docs

注:c filter pおよびc withFilter pは、前者が新しいコレクションを作成するのに対し、後者は後続のmapflatMapforeach、およびwithFilter操作のドメインのみを制限することです。

したがって、filterは元のコレクションを取得して新しいコレクションを生成しますが、withFilterはフィルタリングされていない値を後のmap/flatMap/withFilter呼び出し、(フィルターされた)コレクションの2番目のパスを保存します。したがって、これらの後続のメソッド呼び出しにパススルーするときは、より効率的です。

実際、withFilterは、これらのメソッドのチェーンを操作するために特別に設計されています。これには他のメソッド(forall/existsなど)は必要ないため、FilterMonadicの戻り型withFilterには追加されていません。

115
Shadowlands

Shadowlandsの優れた答え に加えて、filterwithFilterの違いの直感的な例を紹介したいと思います。

次のコードを考えてみましょう

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

ほとんどの人は、resultList(1)と等しいことを期待しています。これは、Scala 2.8、for-comprehensionは

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

ご覧のとおり、翻訳は条件をwithFilterの呼び出しに変換します。 Prior 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 方法。

リファレンス:-p.120、Scala in action(covers Scala 2.10)、Manning Publications、Milanjan Raychaudhuri-- 理解のための翻訳に関するOderskyの考え

7
ZenLulz

Forall/exists部分の場合:

someList.filter(conditionA).forall(conditionB)

と同じになります(ただし、少し直感的ではありません)

!someList.exists(conditionA && !conditionB)

同様に、.filter()。exists()は1つのexists()チェックに結合できますか?

0
lznt

forall/existsが実装されていないための主な理由は、ユースケースが次のとおりであることです。

  • withFilterを無制限に無限ストリーム/反復可能に適用できます
  • 別のwithFilterを遅延的に適用できます(何度も何度も)

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オブジェクトを元のタイプに戻す(コレクション、ストリーム、イテレーターなど)

0
frhack