過去記事インデックス
- Reactive Extensions再入門 その1
- Reactive Extensions再入門 その2「IObservableインターフェースとIObserverインターフェース」
- Reactive Extensions再入門 その3「IObservableのファクトリメソッド」
- Reactive Extensions再入門 その4「Timer系のファクトリメソッド」
- Reactive Extensions再入門 その5「HotとCold」
- Reactive Extensions再入門 その6「HotなIObservableを作成するファクトリ」
- Reactive Extensions再入門 その7「LINQスタイルの拡張メソッド」
- Reactive Extensions再入門 その8「SkipとTakeメソッド」
- Reactive Extensions再入門 その9「Skip + Take + Repeat = ドラッグ」
- Reactive Extensions再入門 その10「Doメソッド」
- Reactive Extensions再入門 その11「Catchメソッド」
- Reactive Extensions再入門 その12「Finallyメソッドとリソース解放」
- Reactive Extensions再入門 その13「最後の値を取得するLatestとMostRecentメソッド」
- Reactive Extensions再入門 その14「Nextメソッド」
- Reactive Extensions再入門 その15「To*****系メソッド」
- Reactive Extensions再入門 その16「最大、最少、平均を求めるメソッド」
- Reactive Extensions再入門 その17「集計するメソッド」
- Reactive Extensions再入門 その18「CountメソッドとLongCountメソッド」
- Reactive Extensions再入門 その19「AnyメソッドとAllメソッド」
- Reactive Extensions再入門 その20「GroupByメソッドでグルーピングしてみよう」
- Reactive Extensions再入門 その21「GroupByUntilメソッド」
- Reactive Extensions再入門 その22「単一の値を取得するメソッド」
- Reactive Extensions再入門 その23「重複を排除するメソッド」
- Reactive Extensions再入門 その24「単一の値を取得するメソッド その2」
- Reactive Extensions再入門 その25「値をまとめるBufferメソッド」
- Reactive Extensions再入門 その26「値をまとめるWindowメソッド」
はじめに
また、しばらく間があいていましたがマイペースでいきます。
Sampleメソッド
ここでは、Sampleメソッドについて説明します。Sampleメソッドは、指定した間隔(時間や任意のタイミング)で最後に発行された値を後続に流すメソッドになります。大量の値が発行されるようなIObservable
メソッドのシグネチャを下記に示します。
public static IObservable<T> Sample<T>( this IObservable<T> source, TimeSpan interval);
このオーバーロードは、時間で値をフィルタリングします。もう1つ任意の間隔で後続に最後の値を流すオーバーロードは下記のようなシグネチャになっています。
public static IObservable<T> Sample<T, TSample>( this IObservable<T> source, IObservable<TSample> sampler);
このオーバーロードは、IObservable
コード例を以下に示します。
var r = new Random(); var subscriber = Observable // 100msの間隔で .Interval(TimeSpan.FromMilliseconds(100)) // 0〜99の乱数を発生させる .Select(_ => r.Next(100)) // 値が発行されたことを確認するためのダンプ .Do(i => Console.WriteLine("{0:HH:mm:ss} Dump {1}", DateTime.Now, i)) // 1秒間隔で最後に発行された値を後続に流す .Sample(TimeSpan.FromMilliseconds(1000)) // 購読 .Subscribe( // 値を表示 i => Console.WriteLine("{0:HH:mm:ss} OnNext {1}", DateTime.Now, i)); Console.WriteLine("Please enter key"); Console.ReadLine(); // 購読終了 subscriber.Dispose();
100ミリ秒間隔で0〜99の値を発行しています。この値をSampleメソッドを使って1秒間隔で最後に発行された値に絞り込んでSubscribeで結果を表示しています。実行結果を以下に示します。
Please enter key 23:13:23 Dump 63 23:13:23 Dump 0 23:13:23 Dump 36 23:13:23 Dump 18 23:13:23 Dump 53 23:13:24 Dump 65 23:13:24 Dump 63 23:13:24 Dump 95 23:13:24 Dump 39 23:13:24 Dump 44 23:13:24 OnNext 44 <- ここ 23:13:24 Dump 72 23:13:24 Dump 91 23:13:24 Dump 36 23:13:24 Dump 37 23:13:24 Dump 68 23:13:25 Dump 69 23:13:25 Dump 98 23:13:25 Dump 67 23:13:25 Dump 79 23:13:25 Dump 23 23:13:25 OnNext 23 <- ここ 23:13:25 Dump 6 23:13:25 Dump 53 23:13:25 Dump 22 23:13:25 Dump 47 23:13:25 Dump 94 23:13:26 Dump 67 23:13:26 Dump 99 23:13:26 Dump 2 23:13:26 Dump 70 23:13:26 Dump 76 23:13:26 OnNext 70 <- ここ 23:13:26 Dump 82
長い実行結果になりますが、Dumpが大量に表示されていることから100msごとに乱数が発生していることが確認できます。その中でSubscribeのOnNextまで渡っている値(実行結果の中で <-ここ で示している箇所)は1秒間隔になっていることが確認できます。
上記の例では、発行される値の間隔に比べてSampleで取得する値をフィルタリングするように設定していましたが、逆に値は10秒間隔で発行されるのに対してSampleメソッドで8秒でフィルタリングしたときに、どのような挙動になるのかを確認したいと思います。コード例を下記に示します。
var r = new Random(); var subscriber = Observable // 10秒間隔で .Interval(TimeSpan.FromSeconds(10)) // 乱数を発生させる .Select(_ => r.Next(100)) // 発生した乱数を表示 .Do(i => Console.WriteLine("{0:HH:mm:ss} Dump {1}", DateTime.Now, i)) // 8秒間隔でフィルタリングする .Sample(TimeSpan.FromSeconds(8)) .Subscribe( // 渡ってきた値を表示する i => Console.WriteLine("{0:HH:mm:ss} OnNext {1}", DateTime.Now, i)); Console.WriteLine("Please enter key"); Console.ReadLine(); // 購読解除 subscriber.Dispose();
実行結果は以下のようになります。
Please enter key 23:23:20 Dump 1 23:23:20 OnNext 1 23:23:22 Dump 39 23:23:22 OnNext 39 23:23:24 Dump 91 23:23:24 OnNext 91 23:23:26 Dump 61 23:23:26 OnNext 61
結果からわかるように、Sampleメソッドは、8秒待っても値が発行されない(元のシーケンスは10秒間隔での値の発行のため)ので、値が発行されなかった場合は何もせず次のタイミングを待っています、次のタイミングで値がきていたら後続に値を流す動きをします。
IObservable