別のオブザーバブルの値に基づいてオブザーバブルをフィルタリングする方法を見つけようとしています。たとえば、時間 x と y の間のイベントのみを受信したいとします。タイマーの値に基づいてオブザーバブルをフィルタリングできますか?
2 に答える
Brandonが述べたように、イベント ストリームを組み合わせる方法はたくさんあります。
とのリアクティブ結合Observable.Join
は非常に汎用的なツールですが、演算子の Rx 組み込みライブラリのかなりの部分が、別のフィルターに基づくフィルター処理をサポートできる方法でストリームを結合します。
Select
Brandon の+Switch
テクニック (私から +1)が本当に好きです。将来の使用のためにそれをファイルしました!
これは、ソース ストリームを開始時間と終了時間にフィルター処理するという前述の問題に直接取り組むアプローチです。Select
+に比べて次のような利点がありますSwitch
。
- ソース ストリームのすべてのイベントのフィルター条件をチェックすることを回避します。
- 「空の」ストリームが不要になります。
- ソースに一度だけサブスクライブします。
OnCompleted()
ソースストリームが続く限り続くのではなく、終了時間に達するとすぐに送信します。
これは実際には、Observable.Window
オペレーターの特定のオーバーロードに要約されますが、順を追って説明します。
Window
基本的な考え方は、開始時間に開き、終了時間に閉じる を適用してソース ストリームをフィルタリングすることです。
xs
最初に、1 秒のパルスと開始時間と終了時間のサンプル ソース ストリーム ( ) を作成します。
var xs = Observable.Interval(TimeSpan.FromSeconds(1));
var startTime = DateTime.Now + TimeSpan.FromSeconds(5);
var endTime = DateTime.Now + TimeSpan.FromSeconds(8);
簡潔にするために、startTime
beforeであることを確認していないことに注意してくださいendTime
。次に、ウィンドウを開くストリームと、ウィンドウを閉じるストリームを作成します。
var start = Observable.Timer(startTime);
var end = Observable.Timer(endTime);
最後に、 を使用してソース ストリームをフィルタリングしますObservable.Window
。このオペレーターの出力は、ストリームのストリーム ( IObservable<IObservable<T>>
) です。各サブストリームは新しいウィンドウです。
使用するオーバーロードは、イベントが新しいウィンドウの開始をマークするストリームと、ウィンドウの開始をトリガーしたイベントを指定して終了ストリームを提供するファクトリ関数を受け入れます。
Timer ストリームを使用すると、開始時刻に作成され、終了時刻に閉じられるウィンドウが 1 つだけあることがわかります。
以下を使用して、ストリームのストリームを平坦化しますObservable.Merge
。
var filtered = xs.Window(start, _ => end).Merge();
これをサブスクライブすると、次のようになります。
filtered.Subscribe(Console.WriteLine);
期待どおり、次の出力が得られます。
4
5
6
繰り返しますが、この問題を解決するには、 を使用するだけでなく、非常に多くの方法がありますWindow
。また、このソリューションを簡単に拡張して、たとえば、複数のウィンドウをサポートすることもできます (開店時間ストリームと閉店時間ストリーム ファクトリを使用することにより)。