RxJavaのフラットマップとスイッチマップの違いは何ですか?


149

rxjavaドキュメントの switchmapの定義はかなり曖昧であり、それはにリンク同じページ flatmapとして。2つの演算子の違いは何ですか?


1
それについてフラットマップと同じページにリンクしています。それは本当に本当です。しかし、言語固有の情報セクションまでスクロールして、興味深い演算子を開きます。これはTOCから自動的に行われるべきだと思いますが、... javadocでも同じ画像を見ることができます。
Ruslan Stelmachenko 2016年

回答:


180

ドキュメントによると(http://reactivex.io/documentation/operators/flatmap.html

switchMap以下のようなものですflatMapしかし、新たなイベントが観測可能な源から放出されるまで、それが唯一の新しい観測可能からアイテムを放出します。

大理石の図はそれをよく示しています。図の違いに注意してください。

switchMap第二の元の発光(緑色大理石)その第二放射しないマップされた発光(緑色の正方形を第三以降)、元の発光(青色大理石)開始し、すでに第一輻射たマッピングされた発光(ブルーダイヤモンド)。つまり、マッピングされた 2つのグリーン排出のうち、最初のものが発生するだけです。青いひし形がそれを打ち負かしたので、緑色の四角は放出されません。

ではflatMap、マップされた結果はすべて、「古くなった」場合でも出力されます。つまり、マップされた緑の放出の1番目 2番目の両方が発生します- 緑の正方形が放出されます(整合性のあるマップ関数を使用した場合、放出されなかったため、2番目の緑のひし形が表示されます)最初のブルーダイヤモンド)

switchMap switchMapでは、元のオブザーバブルが何か新しいものを放出する場合、以前のエミッションはマップされたオブザーバブルを生成しません。 これは古い結果を回避する効果的な方法です

flatMap

switchMapでは、元のオブザーバブルが何か新しいものを放出する場合、以前のエミッションはマップされたオブザーバブルを生成しません。 これは古い結果を避けるための効果的な方法です


4
ありがとう、図は非常に役に立ちます。switchMapが使用される実際の例を知っていますか?
Julian Go

1
@JulianGoここに例があります:github.com/samuelgruetter/rx-playground/blob/master/…これはを使用します.map(func).switchが、と同じ.switchMap(func)です。
Samuel Gruetter、2015年

2
誰かが実際にswitchMapの例を必要とする場合に備えて、このリンクリンクをたどれば、flatMapの代わりにswicthMapを使用するタイミングがわかります。
hermannovich 2016年

2
RxJs5を使用してベン・レッシュからSwitchMapを使用して例えば-ここでは分25-26参照- youtube.com/watch?v=3LKMwkuK0ZEを 、flatmapは既に理解されていた私のために...
arcseldon

7
大理石の図はそれをよく示していますか?何?多分あなたはすでにスイッチマップを理解していると思います。
Helzgate 2017年

166

「インスタント検索」を実装するときに、つまりユーザーがテキストボックスに入力するときに、これに遭遇しました。結果は、キーを押すたびにほぼリアルタイムで表示されます。解決策は次のようです:

  1. 文字列のPublishSubjectなどのサブジェクトを持つ
  2. テキストボックス変更コールバックで、.onNext(text)を呼び出します。
  3. .debounceフィルターをサーバークエリのレート制限に適用する
  4. .switchMapを適用してサーバークエリを実行する-検索用語を取得し、SearchResponseのObservableを返す
  5. SearchResponseを使用してUIを更新するメソッドで.subscribeを適用します。

flatMapを使用すると、検索応答が順不同になる可能性があるため、検索結果が古くなる可能性があります。これを修正するには、switchMapを使用する必要があります。これにより、新しいオブザーバブルが提供されると、古いオブザーバブルがサブスクライブ解除されることが保証されます。

したがって、要約すると、タイミングに関係なくすべての結果が重要な場合はflatMapを使用し、最後のObservableの問題からの結果のみが発生した場合はswitchMapを使用する必要があります。



95

いいえflatMapの議論は比較して対照的ななしで完全ではないswitchMapconcatMapconcatMapEager

これらのメソッドはすべてFunc1、ストリームをに変換するを受け取りObservableます。違いは、返されたObservableがサブスクライブObservableされたときとサブスクライブ解除されたとき、およびそれらのsの放出____Mapが問題のオペレーターによって放出された場合とそのときです。

  • flatMap放出さObservableれたをできるだけ多くサブスクライブします。(プラットフォームに依存する数値です。たとえば、Androidでは小さい数値です)順序が重要ではなく、排出をできるだけ早くしたい場合に使用します。
  • concatMap最初のサブスクライブをサブスクライブし、前のObservableサブスクライブObservableが完了したときにのみ次のサブスクライブをサブスクライブします。順序が重要で、リソースを節約したいときにこれを使用します。完璧な例は、最初にキャッシュをチェックしてネットワーク呼び出しを延期することです。通常は、不要な作業を行わないようにするために、.first()またはが後に続き.takeFirst()ます。

    http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

  • concatMapEagerほぼ同じように機能しますが、できるだけ多くのサブスクライブ(プラットフォームに依存)しますが、前のバージョンObservableが完了して初めて放出します。実行する必要のある並列処理がたくさんあるが、(flatMapとは異なり)元の順序を維持したい場合に最適です。

  • switchMap最後Observableに遭遇したものをサブスクライブし、以前Observableのすべてのからサブスクライブ解除します。これは、検索提案などの場合に最適です。ユーザーが検索クエリを変更すると、古いリクエストは不要になるため、サブスクライブされず、適切に動作するApiエンドポイントがネットワークリクエストをキャンセルします。

別のスレッドでObservableはないを返す場合subscribeOn、上記のメソッドはすべて同じように動作する可能性があります。ネストさObservableれたが独自のスレッドで動作することを許可すると、興味深い便利な動作が現れます。次に、並列処理から多くの利点を得ることができ、ObservableあなたSubscriberのに興味のないからの購読をインテリジェントに購読解除または購読しない

  • amb興味があるかもしれません。任意の数のObservablesを指定すると、最初Observableに何かを放出するのと同じアイテムを放出します。これは、同じ結果を返すことができる/すべきである複数のソースがあり、パフォーマンスが必要な場合に役立ちます。たとえば、ソートの場合amb、マージソートを使用してクイックソートし、どちらか速い方を使用できます。

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- switchMap vs flatMap私が以前に遭遇したすべての説明は、この重要な側面を逃しました、今、すべてがより明確になりました。ありがとうございました。
Andy Res

55

RxJS 4 ではswitchMap はかつて flatMapLatest と呼ばれていました。

基本的には、最新の Observable からのイベントを渡し、以前のObservableからサブスクライブを解除します。


@EpicPandaForceソースオブザーバブルが放出するたびに最新の値を放出する(1回は放出しない)CombineLatestとは一貫性がありません。
Michael Fry

2
これがswitchMapと呼ばれる理由の1つは、o.map(...)。switch()を使用してこの演算子を自分で実装できるためです。それでも私はそれがmapSwitchであると想像しますが、これは舌をそれほど簡単にロールオフしないようです。
Niall Connaughton

7

Map、FlatMap、ConcatMapおよびSwitchMapは、関数を適用するか、Observableによって発行されたデータを変更します。

  • マップは、ソースのObservableによって発行された各アイテムを変更し、変更されたアイテムを発行します。

  • FlatMap、SwitchMap、およびConcatMapも、放出された各アイテムに関数を適用しますが、変更されたアイテムを返す代わりに、再度データを放出できるObservable自体を返します。

  • FlatMapConcatMapの動作はほとんど同じです。それらは、複数のObservableによって発行されたアイテムをマージし、単一のObservableを返します。

  • FlatMapConcatMapの違いは、アイテムが放出される順序です。
  • FlatMapは放出中にアイテムをインターリーブできます。つまり、放出されたアイテムの順序は維持されません。
  • ConcatMapはアイテムの順序を保持します。ただし、ConcatMapの主な欠点は、各Observableが作業を完了するまで待機する必要があるため、非同期が維持されないことです。
  • SwitchMapFlatMapConcatMapとは少し異なります。SwitchMapは、新しいアイテムが放出を開始するたびに、以前のソースObservableからサブスクライブを解除するため、常に現在のObservableからアイテムを放出します。

1

サンプルコードを探しているなら

/**
 * We switch from original item to a new observable just using switchMap.
 * It´s a way to replace the Observable instead just the item as map does
 * Emitted:Person{name='Pablo', age=0, sex='no_sex'}
 */
@Test
public void testSwitchMap() {
    Observable.just(new Person("Pablo", 34, "male"))
              .switchMap(person -> Observable.just(new Person("Pablo", 0, "no_sex")))
              .subscribe(System.out::println);

}

ここでより多くの例を見ることができますhttps://github.com/politrons/reactive


4
しかし、あなたはそれをflatMapと区別するswitchMapの主要な機能を見逃します-以前のものから登録解除している間、最新のObservableの問題のみです。
Artem Novikov

3
この例では、と置き換えswitchMapflatMapもまったく同じように機能します。
Piotr Wittchen

1

次に、101行の例をもう1つ示します。それは私にとって事を説明します。

言われたように:それは最後のオブザーバブル(もしそうなら最も遅いもの)を取得し、残りを無視します。

結果として:

Time | scheduler | state
----------------------------
0    | main      | Starting
84   | main      | Created
103  | main      | Subscribed
118  | Sched-C-0 | Going to emmit: A
119  | Sched-C-1 | Going to emmit: B
119  | Sched-C-0 | Sleep for 1 seconds for A
119  | Sched-C-1 | Sleep for 2 seconds for B
1123 | Sched-C-0 | Emitted (A) in 1000 milliseconds
2122 | Sched-C-1 | Emitted (B) in 2000 milliseconds
2128 | Sched-C-1 | Got B processed
2128 | Sched-C-1 | Completed

Aが無視されたことがわかります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.