1. 序章

RxJava の紹介に続いて、集計演算子と数学演算子について説明します。

これらの操作は、ソースObservableがすべてのアイテムを発行するのを待つ必要があります。このため、これらの演算子は、非常に長いまたは無限のシーケンスを表す可能性があるObservablesで使用すると危険です。

次に、すべての例でTestSubscriberのインスタンスを使用します。ユニットテストに使用できる特定の種類のSubscriberを使用して、アサーションの実行、受信したイベントの検査、またはモックされた[X218X ]サブスクライバー。

それでは、数学演算子について見ていきましょう。

2. 設定

追加の演算子を使用するには、追加の依存関係 pom.xml:に追加する必要があります。

<dependency>
    <groupId>io.reactivex</groupId>
    <artifactId>rxjava-math</artifactId>
    <version>1.0.0</version>
</dependency>

または、Gradleプロジェクトの場合:

compile 'io.reactivex:rxjava-math:1.0.0'

3. 数学演算子

MathObservableは数学演算の実行専用であり、その演算子は、数値として評価できる項目を発行する別のObservableを使用します。

3.1. 平均

average 演算子は、単一の値(ソースから発行されたすべての値の平均)を発行します。

それを実際に見てみましょう:

Observable<Integer> sourceObservable = Observable.range(1, 20);
TestSubscriber<Integer> subscriber = TestSubscriber.create();

MathObservable.averageInteger(sourceObservable).subscribe(subscriber);

subscriber.assertValue(10);

プリミティブ値を処理するための4つの同様の演算子があります: averageInteger average Long average Float 、および平均ダブル

3.2. 最大

max 演算子は、検出された最大数を出力します。

それを実際に見てみましょう:

Observable<Integer> sourceObservable = Observable.range(1, 20);
TestSubscriber<Integer> subscriber = TestSubscriber.create();

MathObservable.max(sourceObservable).subscribe(subscriber);

subscriber.assertValue(9);

max 演算子には、比較関数を使用するオーバーロードされたメソッドがあることに注意することが重要です。

数学演算子は数値として管理できるオブジェクトでも機能するという事実を考慮すると、 max オーバーロード演算子を使用すると、カスタムタイプの比較や標準タイプのカスタムソートが可能になります。

アイテムクラスを定義しましょう:

class Item {
    private Integer id;

    // standard constructors, getter, and setter
}

これで、 itemObservable を定義し、 max 演算子を使用して、idが最も高いItemを発行できます。

Item five = new Item(5);
List<Item> list = Arrays.asList(
  new Item(1), 
  new Item(2), 
  new Item(3), 
  new Item(4), 
  five);
Observable<Item> itemObservable = Observable.from(list);

TestSubscriber<Item> subscriber = TestSubscriber.create();

MathObservable.from(itemObservable)
  .max(Comparator.comparing(Item::getId))
  .subscribe(subscriber);

subscriber.assertValue(five);

3.3. 最小

min 演算子は、ソースから最小の要素を含む単一のアイテムを出力します。

Observable<Integer> sourceObservable = Observable.range(1, 20);
TestSubscriber<Integer> subscriber = TestSubscriber.create();

MathObservable.min(sourceObservable).subscribe(subscriber);

subscriber.assertValue(1);

min 演算子には、コンパレータインスタンスを受け入れるオーバーロードされたメソッドがあります。

Item one = new Item(1);
List<Item> list = Arrays.asList(
  one, 
  new Item(2), 
  new Item(3), 
  new Item(4), 
  new Item(5));
TestSubscriber<Item> subscriber = TestSubscriber.create();
Observable<Item> itemObservable = Observable.from(list);

MathObservable.from(itemObservable)
  .min(Comparator.comparing(Item::getId))
  .subscribe(subscriber);

subscriber.assertValue(one);

3.4. 合計

sum 演算子は、ソース Observable:によって発行されたすべての数値の合計を表す単一の値を発行します。

Observable<Integer> sourceObservable = Observable.range(1, 20);
TestSubscriber<Integer> subscriber = TestSubscriber.create();

MathObservable.sumInteger(sourceObservable).subscribe(subscriber);

subscriber.assertValue(210);

プリミティブに特化した同様の演算子もあります: sumInteger sum Long sum Float 、および[X136X ] sum Double

4. 集計演算子

4.1. 連結

concat オペレーターは、ソースから放出されたアイテムを結合します

次に、2つの Observables を定義し、それらを連結してみましょう。

List<Integer> listOne = Arrays.asList(1, 2, 3, 4);
Observable<Integer> observableOne = Observable.from(listOne);

List<Integer> listTwo = Arrays.asList(5, 6, 7, 8);
Observable<Integer> observableTwo = Observable.from(listTwo);

TestSubscriber<Integer> subscriber = TestSubscriber.create();

Observable<Integer> concatObservable = observableOne
  .concatWith(observableTwo);

concatObservable.subscribe(subscriber);

subscriber.assertValues(1, 2, 3, 4, 5, 6, 7, 8);

詳細に入ると、 concat オペレーターは、前のオペレーターが完了するまで、渡される追加のObservableごとにサブスクライブして待機します。

このため、アイテムの放出をすぐに開始する「ホット」 Observable を連結すると、以前のすべてのアイテムが完了する前に「ホット」Observableが放出するアイテムが失われます。 。

4.2. カウント

count 演算子は、ソースによって発行されたすべてのアイテムのカウントを発行します。

Observableによって放出されたアイテムの数を数えましょう。

List<String> lettersList = Arrays.asList(
  "A", "B", "C", "D", "E", "F", "G");
TestSubscriber<Integer> subscriber = TestSubscriber.create();

Observable<Integer> sourceObservable = Observable
  .from(lettersList).count();
sourceObservable.subscribe(subscriber);

subscriber.assertValue(7);

ソースObservableがエラーで終了した場合、countはアイテムを発行せずに通知エラーを渡します。 ただし、まったく終了しない場合、countはアイテムを発行も終了もしません。

count 操作の場合、 countLong 演算子もあり、 Long 値を出力します。これらのシーケンスは、countLongの容量を超える可能性があります。 X181X]整数。

4.3. リデュース

reduce 演算子は、アキュムレータ関数を適用することにより、放出されたすべての要素を1つの要素に削減します。

このプロセスは、すべてのアイテムが発行されるまで続き、 Observable、 reduceからのは関数から返された最終値を発行します。

ここで、 String のリストを逆の順序で連結して、リストの縮小を実行する方法を見てみましょう。

List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G");
TestSubscriber<String> subscriber = TestSubscriber.create();

Observable<String> reduceObservable = Observable.from(list)
  .reduce((letter1, letter2) -> letter2 + letter1);
reduceObservable.subscribe(subscriber);

subscriber.assertValue("GFEDCBA");

4.4. 収集

collect演算子はreduce演算子に似ていますが、要素を単一の可変データ構造に収集するための専用です。

2つのパラメータが必要です。

  • 空の可変データ構造を返す関数
  • データ構造と発行されたアイテムが与えられると、データ構造を適切に変更する関数

Observableからアイテムのsetを返すことができる方法を見てみましょう。

List<String> list = Arrays.asList("A", "B", "C", "B", "B", "A", "D");
TestSubscriber<HashSet> subscriber = TestSubscriber.create();

Observable<HashSet<String>> reduceListObservable = Observable
  .from(list)
  .collect(HashSet::new, HashSet::add);
reduceListObservable.subscribe(subscriber);

subscriber.assertValues(new HashSet(list));

4.5. ToList

toList 演算子は、 collect 操作と同じように機能しますが、すべての要素を1つのリストに収集します。StreamAPIの Collectors.toList()について考えてみてください。
Observable<Integer> sourceObservable = Observable.range(1, 5);
TestSubscriber<List> subscriber = TestSubscriber.create();

Observable<List<Integer>> listObservable = sourceObservable
  .toList();
listObservable.subscribe(subscriber);

subscriber.assertValue(Arrays.asList(1, 2, 3, 4, 5));

4.6. ToSortedList

前の例と同じですが、発行されたリストはソートされています。

Observable<Integer> sourceObservable = Observable.range(10, 5);
TestSubscriber<List> subscriber = TestSubscriber.create();

Observable<List<Integer>> listObservable = sourceObservable
  .toSortedList();
listObservable.subscribe(subscriber);

subscriber.assertValue(Arrays.asList(10, 11, 12, 13, 14));

ご覧のとおり、 toSortedList はデフォルトの比較を使用しますが、カスタムコンパレータ関数を提供することも可能です。 これで、カスタムの並べ替え関数を使用して整数を逆の順序で並べ替えることができる方法を確認できます。

Observable<Integer> sourceObservable = Observable.range(10, 5);
TestSubscriber<List> subscriber = TestSubscriber.create();

Observable<List<Integer>> listObservable 
  = sourceObservable.toSortedList((int1, int2) -> int2 - int1);
listObservable.subscribe(subscriber);

subscriber.assertValue(Arrays.asList(14, 13, 12, 11, 10));

4.7. ToMap

toMap オペレーターは、 Observable によって発行されたアイテムのシーケンスを、指定されたキー関数によってキー設定されたマップに変換します。

特に、 toMap 演算子には、次のパラメーターの1つ、2つ、または3つを必要とするさまざまなオーバーロードメソッドがあります。

  1. アイテムからキーを生成するkeySelector
  2. 放出されたアイテムからマップに保存される実際の値を生成するvalueSelector
  3. アイテムを保持するコレクションを作成するmapFactory

簡単なクラスBookの定義を始めましょう。

class Book {
    private String title;
    private Integer year;

    // standard constructors, getters, and setters
}

これで、発行された一連のBookアイテムをMapに変換し、本のタイトルをキー、年を値とする方法を確認できます。

Observable<Book> bookObservable = Observable.just(
  new Book("The North Water", 2016), 
  new Book("Origin", 2017), 
  new Book("Sleeping Beauties", 2017)
);
TestSubscriber<Map> subscriber = TestSubscriber.create();

Observable<Map<String, Integer>> mapObservable = bookObservable
  .toMap(Book::getTitle, Book::getYear, HashMap::new);
mapObservable.subscribe(subscriber);

subscriber.assertValue(new HashMap() {{
  put("The North Water", 2016);
  put("Origin", 2017);
  put("Sleeping Beauties", 2017);
}});

4.8. ToMultiMap

マッピングする場合、多くの値が同じキーを共有することは非常に一般的です。 1つのキーを複数の値にマップするデータ構造は、マルチマップと呼ばれます。

これは、 toMultiMap 演算子を使用して実現できます。この演算子は、Observableによって発行されたアイテムのシーケンスをListに変換します。これは、指定されたキー関数によってキー設定されたマップでもあります。 。

この演算子は、別のパラメーターをパラメーターに追加します toMap 演算子、 collectionFactory。 このパラメーターを使用すると、値を格納するコレクションの種類を指定できます。 これがどのように行われるか見てみましょう:

Observable<Book> bookObservable = Observable.just(
  new Book("The North Water", 2016), 
  new Book("Origin", 2017), 
  new Book("Sleeping Beauties", 2017)
);
TestSubscriber<Map> subscriber = TestSubscriber.create();

Observable multiMapObservable = bookObservable.toMultimap(
  Book::getYear, 
  Book::getTitle, 
  () -> new HashMap<>(), 
  (key) -> new ArrayList<>()
);
multiMapObservable.subscribe(subscriber);

subscriber.assertValue(new HashMap() {{
    put(2016, Arrays.asList("The North Water"));
    put(2017, Arrays.asList("Origin", "Sleeping Beauties"));
}});

5. 結論

この記事では、RxJava内で使用可能な数学演算子と集計演算子、そしてもちろん、それぞれの使用方法の簡単な例について説明しました。

いつものように、この記事のすべてのコード例は、Githubにあります。