【UniRx】メッセージ同士の合成 #97
前回の成果
Observable自体を合成するオペレータについて学んだ。
今回やること
今回はメッセージ同士の合成についてまとめます。
- 前回の成果
- 今回やること
- 前回のメッセージの結果と今回の結果を使用したい
- メッセージを指定した数、まとめたい
- 指定したObservableにメッセージが発行されるまでメッセージをまとめる
- 直線のメッセージと今回のメッセージの2つをセットにしたい
- 参考サイト様
前回のメッセージの結果と今回の結果を使用したい
Scan
Scanで、前回の結果と今回の結果を使用することができます。
前回のメッセージの値と今回の値を加算する
/// <summary> /// 前回のメッセージの値と今回の値を加算する /// </summary> private void ExcuteScanList() { Observable .Range(1, 5) .Scan((a, b) => a + b) .Subscribe(x => { Debug.Log(string.Format("ScanList onNext : " + x)); }, () => { Debug.Log(string.Format("ScanList onCompleted")); }); }
結果
Rangeで今回は1~5までの値を流しています。
それをScanを使用することにより加算しています。
何かキーが押されるたびにカウントされる
/// <summary> /// 何かキーが押されるたびにカウントされる /// </summary> private void ExcuteScanOnAnyKeyDown() { Observable .EveryUpdate() .Where(_ => Input.anyKeyDown) .Select(_ => 1) .Scan((a, b) => a + b) .Subscribe(x => { Debug.Log(string.Format("ScanOnAnyKeyDown onNext : " + x)); }, () => { Debug.Log(string.Format("ScanOnAnyKeyDown onCompleted")); }); }
結果
何かキーが押される度にSelectが1を返してくれ、Scanを併せて使用することによりカウントを実装しています。
これにより、変数を用意しなくてもカウントを実装できます。
メッセージを指定した数、まとめたい
Buffer
Bufferは指定した数メッセージをまとめる機能と、指定した数メッセージをスキップする機能があります。
定義は以下のようになっており、Countはまとめる数、Skipは飛ばす数となっております。
Skipを指定しない場合、Countと同じ数飛ばします。
/// <summary> /// メッセージをまとめる /// </summary> /// <param name="source">ストリーム</param> /// <param name="count">まとめるメッセージ数</param> /// <param name="skip">飛ばすメッセージ数</param> public static IObservable<IList<T>> Buffer<T>(this IObservable<T> source, int count, int skip)
メッセージを複数にまとめる、引数1つ
/// <summary> /// メッセージを複数にまとめる /// 引数1つ /// </summary> private void ExcuteBufferSingle() { Observable .Range(1, 5) .Select(x => x.ToString()) // Buffer(2, 2)と同じ .Buffer(2) .Subscribe(x => { Debug.Log("Buffer : " + x.Aggregate<string>((sum, n) => sum.ToString() + ", " + n.ToString())); }, () => { Debug.Log(string.Format("Buffer onCompleted")); }); }
結果
Rangeで1~5の値が渡され、それが2つずつまとめられて、2つスキップされています。
最後の5は2つまとめることが出来ないので、そのまま流しています。
メッセージを複数にまとめる、引数2つ
/// <summary> /// メッセージを複数にまとめる /// 引数2つ /// </summary> private void ExcuteBufferDouble() { Observable .Range(1, 5) .Select(x => x.ToString()) .Buffer(3, 2) .Subscribe(x => { Debug.Log("Buffer : " + x.Aggregate<string>((sum, n) => sum.ToString() + ", " + n.ToString())); }, () => { Debug.Log(string.Format("Buffer onCompleted")); }); }
結果
Bufferの第2引数を指定することでスキップする数を変更することができます。
今回は2を指定したので、2つずつスキップされます。
最後の5は3つまとめることが出来ないので、そのまま流しています。
指定したObservableにメッセージが発行されるまでメッセージをまとめる
Buffer
Bufferの引数にObservableを指定することもできます。
そうした場合、指定したObservableにメッセージが来るまでメッセージをまとめることができます。
ダブルクリック検知
/// <summary> /// 指定したObservableにメッセージが発行されるまでメッセージをまとめる /// ダブルクリック検知 /// </summary> private void ExcuteBufferDoubleClick() { // クリック検知 IObservable<Unit> clickObservable = this.UpdateAsObservable() .Where(_ => Input.GetMouseButtonDown(0)); clickObservable // 200ms内のクリックをまとめる .Buffer(clickObservable.Throttle(TimeSpan.FromMilliseconds(200))) .Where(x=> x.Count == 2) .Subscribe(x => { Debug.Log("Buffer : Double Click"); }, () => { Debug.Log(string.Format("Buffer onCompleted")); }); }
結果
Throttleは指定した時間経過後にonNextを発行するオペレータです。
Whereを使用して、2回カウントが来たらというフィルターをかけてあげます。
この2つとBufferを組み合わせることにより、ダブルクリックを検知することができます。
今回の場合、200ms以内に2回クリックをするとメッセージが発行されます。
直線のメッセージと今回のメッセージの2つをセットにしたい
PairWise
PairWiseを使用することで、前回のメッセージと今回のメッセージを1つにまとめることができます。
Buffer(2, 1)と挙動が似ていますが、こちらは必ず2つで1セットになることが違いになります。
2つのメッセージを1つにまとめる
/// <summary> /// 2つのメッセージを1つにまとめる /// Buffer(2, 1)との違いは必ず2つでセットになること /// </summary> private void ExcutePairwise() { Observable .Range(1, 5) // 2つのメッセージを1つにまとめる .Pairwise() .Subscribe(x => { Debug.Log(string.Format("Pairwise : {0}, {1}", x.Previous, x.Current)); }, () => { Debug.Log(string.Format("Pairwise : onCompleted")); }); // 比較用 Observable .Range(1, 5) .Select(x => x.ToString()) .Buffer(2, 1) .Subscribe(x => { Debug.Log("Buffer : " + x.Aggregate<string>((sum, n) => sum.ToString() + ", " + n.ToString())); }, () => { Debug.Log(string.Format("Buffer : onCompleted")); }); }
結果
Buffer(2, 1)と実際に比較してみると、最後のメッセージが異なります。
Pairwiseは必ず2つをまとめたメッセージが流れてきていますが、Bufferは1つでも関係なく流れています。
今回は以上となります。
ここまでご視聴ありがとうございました。