過去記事インデックス
- 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*****系メソッド」
はじめに
今回は、最大値、最小値、平均を求めるメソッドについて説明します。簡単なようで、ちょっとだけ奥深い感じですね。
MaxメソッドとMinメソッドとAverageメソッド
ここでは、IObservable
var s = new Subject<int>(); // 最大値を求めて表示 s.Max().Subscribe(max => { Console.WriteLine("Max {0}", max); }, () => Console.WriteLine("Max Completed")); // 最小値を求めて表示 s.Min().Subscribe(min => { Console.WriteLine("Min {0}", min); }, () => Console.WriteLine("Min Completed")); // 平均を求めて表示 s.Average().Subscribe(avg => { Console.WriteLine("Average {0}", avg); }, () => Console.WriteLine("Average Completed")); // 値の発行〜完了通知 Console.WriteLine("OnNext(1-3)"); s.OnNext(1); s.OnNext(2); s.OnNext(3); Console.WriteLine("OnCompleted()"); s.OnCompleted();
実行結果を下記に示します。
OnNext(1-3) OnCompleted() Max 3 Max Completed Min 1 Min Completed Average 2 Average Completed
1〜3の値を発行しているので、最大値が3、最小値が1、平均が2という結果になっていることが確認できます。MaxメソッドやMinメソッドやAverageメソッドには数値を表す型と、それらの型のnullable型に対応するオーバーロードが定義されています。MaxとMinは、その型の最大値と最小値、Averageはdouble型で平均値のIObservableを返します。上記のコード例では、IObservable
また、MaxとMinメソッドには、独自の比較方法を指定するためのIComparer
// Tuple<int, int>の比較を行うクラス class TupleIntIntComparer : IComparer<Tuple<int, int>> { // Item1 + Item2の結果で比較を行う public int Compare(Tuple<int, int> x, Tuple<int, int> y) { if (x == y) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } var xValue = x.Item1 + x.Item2; var yValue = y.Item1 + y.Item2; return Comparer<int>.Default.Compare(xValue, yValue); } } // ----------------------------------------- // 最大値を求めて表示 s.Max(new TupleIntIntComparer()).Subscribe(max => { Console.WriteLine("Max {0}", max); }, () => Console.WriteLine("Max Completed")); // 最小値を求めて表示 s.Min(new TupleIntIntComparer()).Subscribe(min => { Console.WriteLine("Min {0}", min); }, () => Console.WriteLine("Min Completed")); // 値の発行〜完了通知 Console.WriteLine("OnNext"); s.OnNext(Tuple.Create(1, 1)); s.OnNext(Tuple.Create(1, 2)); s.OnNext(Tuple.Create(3, 1)); Console.WriteLine("OnCompleted()"); s.OnCompleted();
実行結果を下記に示します。
OnNext OnCompleted() Max (3, 1) Max Completed Min (1, 1) Min Completed
このようにして、最大、最小を求める際の比較ロジックをカスタマイズすることが出来ます。
MaxByメソッドとMinByメソッド
ここでは、MaxByメソッドとMinByメソッドについて説明します。このメソッドは最大値、最小値を求めるという意味ではMaxメソッドとMinメソッドと同じですが、引数に最大と最小を求めるためのキーとなる値を取得するためのFunc
var s = new Subject<Tuple<int, int>>(); // 最大値を求めて表示, 比較はタプルのItem1を使用する s.MaxBy(t => t.Item1).Subscribe(max => { foreach (var i in max) { Console.WriteLine("MaxBy {0}", i); } }, () => Console.WriteLine("MaxBy Completed")); // 最小値を求めて表示, 比較はタプルのItem1を使用する s.MinBy(t => t.Item1).Subscribe(min => { foreach (var i in min) { Console.WriteLine("MinBy {0}", i); } }, () => Console.WriteLine("MinBy Completed")); // 値の発行〜完了通知 Console.WriteLine("OnNext"); s.OnNext(Tuple.Create(1, 1)); s.OnNext(Tuple.Create(1, 2)); s.OnNext(Tuple.Create(3, 1)); Console.WriteLine("OnCompleted()"); s.OnCompleted();
実行結果を下記に示します。
OnNext OnCompleted() MaxBy (3, 1) MaxBy Completed MinBy (1, 1) MinBy (1, 2) MinBy Completed
MinByメソッドの結果が2つあることが確認できます。これはItem1の値が1になるタプルが(1, 1)と(1, 2)の2種類あるためです。このようなケースに対応するために、IObservable
また、ManByメソッドとMixByメソッドにも、比較方法をカスタマイズできるIComparer
まとめ
個人的にはMinByやMaxByがIList