RxJS Mastery – #71 Mathematical and Aggregator Operators

RxJS provides some handy utility operators. Count, max, min, and reduce are the ones we have a look at in this article.

RxJS count returns the number of values

The RxJS count operator emits the number of values once the source completes. Below the source emits the values a, b, and c. This is why count is returning 3 at the 4th timeframe (together with the completion).

const result$ = cold('abc|').pipe(
    count()
);

expectObservable(result$).toBe(
    '---(d|)', { d: 3 }
);

The operator also works with a condition. This gives us the possibility to count the values matching a predicate. In the below example, we are counting the numbers greater than 2.

const result$ = cold<number>('1234|').pipe(
    count(v => v > 2)
);

expectObservable(result$).toBe(
    '----(d|)', { d: 2 }
);

RxJS max and min

Also for the RxJS max and min operators the completion time of the source Observable is decisive. Because only at that time all values are known and, as the name suggests, the maximal or minimal value is emitted.

const result$ = cold<number>('8923402|').pipe(
    max()
);

expectObservable(result$).toBe(
    '-------(r|)', { r: '9' }
);

Similarly, the number 0 is found when applying min:

const result$ = cold<number>('8923402|').pipe(
    min()
);

expectObservable(result$).toBe(
    '-------(r|)', { r: '0' }
);

The operator works by default with numbers but also accepts a comparator function to compare objects. Let us try to find the cheapest product:

type product = { name: string, price: number }
const result$ = cold<product>('abc|',
    {
        a: { name: 'Book', price: 10 },
        b: { name: 'Video', price: 15 },
        c: { name: 'Course', price: 20 },
    }).pipe(
    min((a, b) => a.price < b.price ? -1 : 1)
);

expectObservable(result$).toBe(
    '---(r|)', { r: { name: 'Book', price: 10 } }
);

The cheapest one is the Book with a price of 10.

RxJS reduce

Most of you probably know the reduce function typically available in most languages. Reduce applies an accumulator function on each value which allows to combining past values with new ones. Optionally a seed can be specified as a starting value.
In our example, we simply sum up numbers and start with a seed value of 0:

const result$ = cold<number>('8923402|').pipe(
    reduce((a, b) => Number(a) + Number(b), 0)
);

expectObservable(result$).toBe(
    '-------(r|)', { r: 28 }
);

As with every operator in this article, the emission happens once the source completes.

Exercise for the RxJS mathematical and aggregator operators 💪

Build RxJS reduce by combining the scan operator with the last operator.

This post is part of the RxJS mastery series. As always the code examples can be found on GitHub.