57

マップ、フラットマップなどの関数を適用するときに、フィルタの代わりにwithFilterを使用すると、よりパフォーマンスが向上しますか?with filterフィルタの代わりに

map、flatmap、foreachのみがサポートされているのはなぜですか? (forall/likeのような期待される関数)

答えて

93

the Scala docsから:

注:違いc filter pc withFilter pの間にあるのは、前者の が新しいコレクションを作成するのに対し、後者はのドメイン続いてmap,flatMap,foreachおよびwithFilterの操作を含む。

のでfilterは、元のコレクションを取得し、新しいコレクションを作るが、withFilterは非厳密(すなわちなまけ)意志(フィルタを介して第2のパスを保存し、に後でmap/flatMap/withFilter呼び出しによってフィルタリングされていない値を渡します)コレクション。したがって、これらの後続のメソッド呼び出しを通過すると、より効率的になります。

実際には、withFilterは、これらの方法のチェーンで作業するために特別に設計されています。これは理解のために解説されています。これには他の方法(forall/existsなど)は必要ありません。したがって、FilterMonadic戻り値タイプwithFilterには追加されていません。

+0

希望。 – Kigyo

+1

@Kigyo withFilterを自分で使うとは思わない(for-expressionsの中で暗黙のうちに)。マップ/フィルタを遅延させたい場合は 'view'を使います。 –

+0

私は参照してください。 'view'と' withFilter'の正確な違いは何ですか?なぜforループで使われないのですか? – Kigyo

-5

回避策として、mapflatMapだけを使って他の関数を実装することができます。

また、この最適化は収量のために使用

-3

は、例えば、回避することができます...小さなコレクションに無用です:

for { 
    e <- col; 
    if e isNotEmpty 
} yield e.get(0) 
2

the excellent answer of Shadowlandsのほかに、filterwithFilterの違いの直観的な例を紹介したいと思います。

はのは、ほとんどの人はresultList(1)に等しくなるように期待して、次のコード

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

を考えてみましょう。あなたは翻訳がwithFilterへの呼び出しに条件を変換見ることができるようにするために、理解が

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

に翻訳されたので、これは、Scalaの2.8以降の場合です。前のScala 2.8は、のために、理解、次のようなものに翻訳されました:List(1, 2, 3)は:

val r2 = list filter { 
    case i => go 
} map { 
    case i => { 
    go = false 
    i 
    } 
} 

filterを使用して、resultの値はかなり異なるだろう。 goフラグfalseを作成しているという事実は、フィルタが既に行われているため、フィルタには何の影響も与えません。 Scala 2.8では、withFilterを使用してこの問題を解決しました。 withFilterを使用すると、mapメソッド内で要素にアクセスするたびに条件が評価されます。

リファレンス: - P.120、アクションでスカラ(スカラ2.10をカバー)、マニング出版、Milanjan Raychaudhuri - 彼らはまだいくつかの日にこれらのメソッドを追加しOdersky's thoughts about for-comprehension translation

関連する問題