RxJava Mathを使って最大・最小・平均・合計を計算する
RxJavaを最近使うことが多くなってきてストリームに流れているデータ内の最小値と最大値を取ることができないか調べておりました。
そうするとRxJavaのMathというのがありそれで実現できたのでそのやり方とMathの機能についてごしょうかいします。
準備
今回はAndroidで行いましたので次の導入を行って確認しました。
- RxJava
- RxJava Math
- Retrolambda
build.gradleの設定は次のようになります。
[build.gradle]
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.2.0-alpha6' classpath 'me.tatarka:gradle-retrolambda:3.3.0-beta4' } }
[app/build.gradle]
apply plugin: 'com.android.application' apply plugin: 'me.tatarka.retrolambda' android { <省略> compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { <省略> compile 'io.reactivex:rxjava-math:1.0.0' compile 'io.reactivex:rxjava:1.1.8' }
最小値を取り出す
それでは最小値を取り出してみましょう。
最小値はOperatorMinMaxのminを使うと最小値を取り出すことができます。
引数にObservableを渡しストリーム上の数値の中で最小のものをsubscribeします。
実装は次のようになります。
OperatorMinMax.min(Observable.just(12, 16, 11, 8)) .subscribe(value -> { Log.d("techium", "test1 :" + String.valueOf(value)); });
これを実装すると下記のような結果を得ることができます。
08-06 21:11:30.201 17624-17624/? D/techium: test1 :8
これだとデータクラスなどの独自クラスの中で最小などを取得することができません。
そこで第2引数にComparatorで計算させる処理を書くと独自クラスでも最小を取り出すことができます。
実装は次のようになります。
// Comparatorを利用 OperatorMinMax.min(Observable.just(12, 16, 11, 8), (o1, o2) -> { Log.d("techium", "test2 : o1: " + o1 + ", o2: " + o2); return o1 - o2; }) .subscribe(value -> { Log.d("techium", "test2 :" + String.valueOf(value)); });
o1とo2を減算した結果でo1が最小になるように結果を返してあげると最小値が取れます。
実行結果は次のようになります。
08-06 21:11:30.201 17624-17624/? D/techium: test2 : o1: 12, o2: 16 08-06 21:11:30.201 17624-17624/? D/techium: test2 : o1: 12, o2: 11 08-06 21:11:30.201 17624-17624/? D/techium: test2 : o1: 11, o2: 8 08-06 21:11:30.201 17624-17624/? D/techium: test2 :8
注意事項が1点あります。
MathObservableにもminとmaxが定義され、OperatorMinMaxをラップしています。
そのため同じ処理を実施することができますが第2引数のComparatorの処理部分をラップしていないためMathObservableでは使えませんのでOperatorMinMaxを使うことをおすすめします。
最大値を取り出す
最大値の取得は最小値の取得のminをmaxに変えた内容と同じです。
実装は次のようになります。
OperatorMinMax.max(Observable.just(12, 16, 11, 8)) .subscribe(value -> { Log.d("techium", "test1 :" + String.valueOf(value)); }); // Comparatorを利用 OperatorMinMax.max(Observable.just(12, 16, 11, 8), (o1, o2) -> { Log.d("techium", "test2 : o1: " + o1 + ", o2: " + o2); return o1 - o2; }) .subscribe(value -> { Log.d("techium", "test2 :" + String.valueOf(value)); });
実行結果はこちらです。
08-06 21:11:30.201 17624-17624/? D/techium: test1 :16 08-06 21:11:30.201 17624-17624/? D/techium: test2 : o1: 12, o2: 16 08-06 21:11:30.201 17624-17624/? D/techium: test2 : o1: 16, o2: 11 08-06 21:11:30.201 17624-17624/? D/techium: test2 : o1: 16, o2: 8 08-06 21:11:30.201 17624-17624/? D/techium: test2 :16
平均値を取り出す
平均値の取得はMathObservableを使って行います。
残念ながら数値計算しかできないため独自クラスのなかでの平均データを取得するなどはできません。
計算できる型は次のものになります。
- Integer
- Long
- Double
- Float
整数値の平均値を求めるには次のようになります。
MathObservable.averageInteger(Observable.just(12, 16, 11, 8)) .subscribe(value -> { Log.d("techium", String.valueOf(value)); });
実行結果は次のようになります。
08-06 21:11:30.203 17624-17624/? D/techium: 11
averageIntegerの部分をfloatやdoubleに切り替えると型を変更して計算を行えます。
合計値を取り出す
合計値の取得はOperatorSumを使って行います。
残念ながらこちらも数値計算しかできないため独自クラスのなかの合計データを生成するなどはできません。
計算できる型は次のものになります。
- Integer
- Long
- Double
- Float
整数値の合計を求めるには次のようになります。
OperatorSum.sumIntegers(Observable.just(12, 16, 11, 8)) .subscribe(value -> { Log.d("techium", String.valueOf(value)); });
実行結果は次のようになります。
08-06 21:11:30.202 17624-17624/? D/techium: 47