RxJS の Operators (10) - Mathematical and Aggregate Operators

この記事は [bouzuya's RxJS Advent Calendar 2015](http://www.adventar.org/calendars/1200) の 12 日目かつ RxJS Advent Calendar 2015 の 12 日目です。

# はじめに

今日は [ReactiveX の Mathematical and Aggregate Operators](http://reactivex.io/documentation/operators.html#mathematical) について [RxJS の API ドキュメント](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/observable.md)を読んだりサンプルコードを書いたりしていきます。

また [RxJS 4.0.7](https://github.com/Reactive-Extensions/RxJS/tree/v4.0.7) を対象にしています。

# Observable の集約

## `Observable.prototype.average`

- [ReactiveX - Average operator](http://reactivex.io/documentation/operators/average.html)
- [`Observable.prototype.average` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/average.md)
- [`Observable.prototype.average` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/average.js)

平均を流します。

```js
import { Observable } from 'rx';

Observable
  .from([1, 3, 5])
  .average()
  .subscribe(
    value => console.log(`onNext: ${value}`),
    error => console.log(`onError: ${error}`),
    () => console.log('onCompleted')
  );
// onNext: 3
// onCompleted
```

`average` は引数に `selector` を取れるのですが、`count` は引数に `predicate` を取れるので、何を基準にしているのかよく分からないです。

## `Observable.prototype.concat`

`concat` は結合のときに書いてしまったので割愛します。

## `Observable.prototype.count`

- [ReactiveX - Count operator](http://reactivex.io/documentation/operators/count.html)
- [`Observable.prototype.count` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/count.md)
- [`Observable.prototype.count` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/count.js)

```js
import { Observable } from 'rx';

Observable
  .from([1, 2, 3, 4, 5])
  .count()
  .subscribe(
    value => console.log(`onNext: ${value}`),
    error => console.log(`onError: ${error}`),
    () => console.log('onCompleted')
  );
// onNext: 5
// onCompleted
```

前述の通り `predicate` を取れます。`filter` してから `count` すればいいのにと個人的には思ってしまいます。

## `Observable.prototype.max` / `Observable.prototype.min`

- [ReactiveX - Max operator](http://reactivex.io/documentation/operators/max.html)
- [`Observable.prototype.max` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/max.md)
- [`Observable.prototype.max` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/max.js)
- [ReactiveX - Min operator](http://reactivex.io/documentation/operators/min.html)
- [`Observable.prototype.min` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/min.md)
- [`Observable.prototype.min` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/min.js)

最大値 / 最小値を流します。`comparer` を引数に取れます。

```js
import { Observable } from 'rx';

Observable
  .from([1, 4, 5, 2, 3])
  .max()
  .subscribe(
    value => console.log(`onNext: ${value}`),
    error => console.log(`onError: ${error}`),
    () => console.log('onCompleted')
  );
// onNext: 5
// onCompleted
```

ソースコードを見ると `Observable.prototype.maxBy` / `minBy` を使って実装されていることが分かります。

## `Observable.prototype.reduce`

- [ReactiveX - Reduce operator](http://reactivex.io/documentation/operators/reduce.html)
- [`Observable.prototype.reduce` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/reduce.md)
- [`Observable.prototype.reduce` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/reduce.js)

`Array.prototype.reduce` 相当のものです。

```js
import { Observable } from 'rx';

Observable
  .from([1, 2, 3, 4, 5])
  .reduce((sum, i) => sum + i, 0)
  .subscribe(
    value => console.log(`onNext: ${value}`),
    error => console.log(`onError: ${error}`),
    () => console.log('onCompleted')
  );
// onNext: 15
// onCompleted
```

`Observable.prototype.scan` の際にも書きましたが、`reduce` よりも `scan` を使う場面のほうが多いように感じます。

## `Observable.prototype.sum`

- [ReactiveX - Sum operator](http://reactivex.io/documentation/operators/sum.html)
- [`Observable.prototype.sum` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/sum.md)
- [`Observable.prototype.sum` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/sum.js)

合計を返します。

```js
import { Observable } from 'rx';

Observable
  .from([1, 2, 3, 4, 5])
  .sum()
  .subscribe(
    value => console.log(`onNext: ${value}`),
    error => console.log(`onError: ${error}`),
    () => console.log('onCompleted')
  );
// onNext: 15
// onCompleted
```

さきほどの `Observable.prototype.reduce` で `sum` っぽいものを書いてしまいました……。実装自体は `reduce` を使うわけではなく個別に実装されています。

# おわりに

ReactiveX の Mathematical and Aggregate Operators を見ました。

難しい動きのものはなさそうですね。