後でmap、flatmapなどの関数を適用するときに、filterではなくwithFilterを使用する方が常にパフォーマンスが向上しますか?
Map、flatmap、foreachのみがサポートされているのはなぜですか? (forall/existsなどの期待される機能)
から the Scala docs :
注:
c filter p
およびc withFilter p
は、前者が新しいコレクションを作成するのに対し、後者は後続のmap
、flatMap
、foreach
、およびwithFilter
操作のドメインのみを制限することです。
したがって、filter
は元のコレクションを取得して新しいコレクションを生成しますが、withFilter
はフィルタリングされていない値を後のmap
/flatMap
/withFilter
呼び出し、(フィルターされた)コレクションの2番目のパスを保存します。したがって、これらの後続のメソッド呼び出しにパススルーするときは、より効率的です。
実際、withFilter
は、これらのメソッドのチェーンを操作するために特別に設計されています。これには他のメソッド(forall
/exists
など)は必要ないため、FilterMonadic
の戻り型withFilter
には追加されていません。
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
の呼び出しに変換します。 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の考え
Forall/exists部分の場合:
someList.filter(conditionA).forall(conditionB)
と同じになります(ただし、少し直感的ではありません)
!someList.exists(conditionA && !conditionB)
同様に、.filter()。exists()は1つのexists()チェックに結合できますか?
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 => i)と同等であり、ここで変換するために使用されることに注意してくださいwithFilterオブジェクトを元のタイプに戻す(コレクション、ストリーム、イテレーターなど)