なぜflatMapを使用する必要があるのですか?


92

私はRxJSを使い始めましたが、この例でflatMapやのような関数を使用する必要がある理由がわかりませんconcatAll。ここで配列の配列はどこですか?

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(url => {console.log(url)})

誰かが起こっていることを視覚的に説明できれば、非常に役立ちます。


1
この回答は、提供される貴重なリファレンスのために素晴らしいものですが、rxjs用語は英語にうまく翻訳されません。(写真が良いです)。そのため、このような単純な例を実行するか、rxjsリポジトリでより複雑な例を実行し、フラットマップおよびマップ演算子の前後に「.do」演算子を追加して、Chromeデバッガーでブレークポイントを設定することをお勧めします。それぞれが異なる出力を生成することがすぐに
わかり

5
flatMap名前が付けられていればmapThenFlatten、混乱が少ないと思います。
2017年

回答:


73

私が見始めたとき、Rxjs私もその石につまずきました。私を助けたのは次のとおりです:

  • reactx.ioからのドキュメント。たとえば、次の場合flatMaphttp : //reactivex.io/documentation/operators/flatmap.html
  • rxmarblesからのドキュメント:http ://rxmarbles.com/ 。あなたはflatMapそこに見つけられないでしょう、mergeMap代わりに(別の名前)を見なければなりません。
  • 欠落していたRxの概要:https : //gist.github.com/staltz/868e7e9bc2a7b8c1f754。非常によく似た例を扱います。特に、約束は1つの値だけを放出する観測可能なものに似ているという事実に対処します。
  • 最後に、RxJavaからの型情報を調べます。タイプされていないJavascriptはここでは役に立ちません。基本的にif Observable<T>が型Tの値をプッシュする監視可能なオブジェクトを示し、型flatMapの関数をT' -> Observable<T>引数として取り、を返しますObservable<T>mapタイプの関数を取り、T' -> Tを返しますObservable<T>

    例に戻ると、URL文字列からPromiseを生成する関数があります。それでT' : string、そしてT : promise。そして、何から、私たちは前にも言ったpromise : Observable<T''>ように、T : Observable<T''>と、T'' : html。そのpromiseプロデュース関数をに入れるとmap、必要なObservable<Observable<T''>>ときに取得Observable<T''>できhtmlます。つまり、オブザーバブルが値を出力するようにします。flatMapは、からの結果を平坦化(観測可能なレイヤーを削除)するため、そのように呼び出されmapます。あなたの背景によっては、これはあなたにとって中国語かもしれませんが、入力情報とここからの描画ですべてが私にとって非常に明確になりました:http : //reactivex.io/documentation/operators/flatmap.html


2
私はあなたが単純化することができるはずことを言及するのを忘れreturn Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));return jQuery.getJSON(requestUrl);としてflatMapも、タイプの約束すなわち関数を返すセレクタ機能を受け入れますT' -> Promise
user3743222 2015年

2
うわー、そのGitHub Gist(gist.github.com/staltz/868e7e9bc2a7b8c1f754)は流血の幻想的です。RxJSのようなReactiveXライブラリを使用している人には、これをお勧めします。
Jacob Stamm

@JacobStamm同意します。物事を簡単にするだけです。
CruelEngine 2019

この構文はどういう意味T’ -> Tですか?私Tはジェネリックとして理解していますが、アポストロフィと非脂肪矢印とは何ですか?
1252748

T 'をXまたはYで置き換えることができます。答えのどこでも意味を変更する必要はありません。矢印は型署名のHaskell表記です。したがって、T '-> Tは、タイプT'の要素を取り、タイプTの要素を返す関数のシグネチャです
user3743222

124
['a','b','c'].flatMap(function(e) {
    return [e, e+ 'x', e+ 'y',  e+ 'z'  ];
});
//['a', 'ax', 'ay', 'az', 'b', 'bx', 'by', 'bz', 'c', 'cx', 'cy', 'cz']


['a','b','c'].map(function(e) {
    return [e, e+ 'x', e+ 'y',  e+ 'z'  ];
});
//[Array[4], Array[4], Array[4]]

結果がより多くのObservableであるObservableがある場合、flatMapを使用します。

別のオブザーバブルによって生成されたオブザーバブルがある場合、データではなくオブザーバブルがあるため、フィルター、縮小、または直接マッピングすることはできません。オブザーバブルを生成する場合は、マップではなくflatMapを選択します。その後、あなたは大丈夫です。

2番目のスニペットのように、非同期操作を行う場合は、flatMapを使用する必要があります。

var source = Rx.Observable.interval(100).take(10).map(function(num){
    return num+1
});
source.subscribe(function(e){
    console.log(e)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>

var source = Rx.Observable.interval(100).take(10).flatMap(function(num){
    return Rx.Observable.timer(100).map(() => num)
});
source.subscribe(function(e){
    console.log(e)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>


31

flatMap Observableによって放出されたアイテムを新しいObservableに変換し、それらからの放出を単一のObservableにフラット化します。

get("posts")によって「フラット化」されたObservableを返す以下のシナリオを確認してくださいflatMap

myObservable.map(e => get("posts")).subscribe(o => console.log(o));
// this would log Observable objects to console.  

myObservable.flatMap(e => get("posts")).subscribe(o => console.log(o));
// this would log posts to console.

2
素敵でシンプルな答え。これが最高だと思います。
ヴォーン

「flatMapは、Observableによって放出されたアイテムを新しいObservableに変換し、それらからの放出を単一のObservableにフラット化します。」これは素晴らしいものです。
MBak 2018

31

人々は次のような定義を与えることで物事を過度に複雑にする傾向があります。

flatMapは、Observableによって放出されたアイテムをObservablesに変換し、それらからの放出を単一のObservableにフラット化します

私はこの定義がまだ混乱していると誓いますが、例を使用することによって、最も簡単な方法でそれを説明します

私たちの状況:次のような状況を視覚化できるように、必要なデータを含むオブザーバブルを返すHTTP呼び出しを行うために使用するデータ(単純なURL)を返すオブザーバブルがあります。

Observable 1
    |_
       Make Http Call Using Observable 1 Data (returns Observable_2)
            |_
               The Data We Need

ご覧のとおり、必要なデータに直接到達できないため、データを取得する最初の方法は、次のような通常のサブスクリプションのみを使用できます。

Observable_1.subscribe((URL) => {
         Http.get(URL).subscribe((Data_We_Need) => {
                  console.log(Data_We_Need);
          });
});

これは機能しますが、ご覧のとおり、データを取得するためにサブスクリプションをネストする必要がありますが、これは問題ないように見えますが、メンテナンス不能になるネストされたサブスクリプションが10個あると想像してください。

したがって、これを処理するためのより良い方法flatMapは、同じことを行うがネストされたサブスクリプションを回避する演算子を使用することです。

Observable_1
    .flatMap(URL => Http.get(URL))
    .subscribe(Data_We_Need => console.log(Data_We_Need));

19

シンプル:

[1,2,3].map(x => [x, x * 10])
// [[1, 10], [2, 20], [3, 30]]

[1,2,3].flatMap(x => [x, x * 10])
// [1, 10, 2, 20, 3, 30]]

16

配列の配列ではありません。オブザーバブルのオブザーバブルです。

次は、文字列の監視可能なストリームを返します。

requestStream
  .map(function(requestUrl) {
    return requestUrl;
  });

これは、jsonの監視可能なストリームの監視可能なストリームを返しますが

requestStream
  .map(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

flatMap jsonストリームを直接観察できるように、オブザーバブルを自動的にフラット化します


3
この概念を理解するのは難しいです。「jsonの監視可能なストリームの監視可能なストリームを返します」という意味を視覚的に示すコメントを追加できますか。ありがとう。
user233232 2015年

@ user233232、[x、x、x、x]から[[xxx]、[[xxx]、[xxx]]]のような
serkan

最初の文を理解するための鍵は、flatMap(およびmap)が配列に特別ではないことを理解することです。これらの操作は、配列、辞書、「オプション」、リアクティブストリーム、プロミス、ポインタ、さらには関数自体を含む、任意の汎用コンテナまたはラッパーで定義できます。これは、モナドと呼ばれる数学的構造の創発的な特性です。上記のすべての例は、モナドになるための要件を満たしているため、すべてにmapとの定義を与えることができますflatMap(いくつかの注意点があります)。
mklbtz 2018

14

ここでは、サブスクライブを使用したflatMapの同等の実装を示します。

flatMapなし:

this.searchField.valueChanges.debounceTime(400)
.subscribe(
  term => this.searchService.search(term)
  .subscribe( results => {
      console.log(results);  
      this.result = results;
    }
  );
);

flatMapの場合:

this.searchField.valueChanges.debounceTime(400)
    .flatMap(term => this.searchService.search(term))
    .subscribe(results => {
      console.log(results);
      this.result = results;
    });

http://plnkr.co/edit/BHGmEcdS5eQGX703eRRE?p=preview

お役に立てれば幸いです。

オリビエ。


13

Observableは、Next、Error、およびCompletedのイベントのストリームを発行するオブジェクトです。

関数がObservableを返す場合、それはストリームではなく、Observableのインスタンスを返します。flatMapオペレータは、単にストリームにそのインスタンスをマッピングします。

これは、flatMapと比較した場合の動作mapです。指定された関数を実行し、結果のオブジェクトをストリームにフラット化します。


7

flatMapを使用

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(json => {console.log(json)})

flatMapなし

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .map(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(jsonStream => {
  jsonStream.subscribe(json => {console.log(json)})
})

0

flatMapは、Observableによって放出されたアイテムをObservablesに変換し、それらからの放出を単一のObservableにフラット化します

私は愚かではありませんが、これを10回読まなければなりませんでしたが、それでもわかりません。私がコードスニペットを読んだとき:

[1,2,3].map(x => [x, x * 10])
// [[1, 10], [2, 20], [3, 30]]

[1,2,3].flatMap(x => [x, x * 10])
// [1, 10, 2, 20, 3, 30]

それから私は何が起こっているのかを理解することができました、それは2つのことをします:

flatMap

  1. map:*)放出されたアイテムをObservableに変換します。
  2. flat:次に、それらのObservableを1つのObservableとしてマージします。

*)変換という言葉は、アイテムを別の何かに変換できることを示しています。

次に、マージ演算子は明確になり、マッピングなしでフラット化を行います。それをmergeMapと呼ばないのはなぜですか?flatMapのその名前を持つAlias mergeMapもあるようです

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