Skip to content

Recipes

Vitaly Tomilov edited this page Nov 22, 2022 · 59 revisions

Equivalents for frequent operations and well-known operators.

This is only for things not explicitly covered by the API.

You can either use the examples directly, or create Custom Operators from them.


find (first)

Equivalent to find(condition) can have several forms...

  • pipe(iterable, first(condition)) - the simplest, and best-performing
  • pipe(iterable, filter(condition), first())
  • pipe(iterable, filter(condition), take(1))

find (last)

Equivalent to finding the last matching value:

import {pipe, filter, last} from 'iter-ops';

pipe(iterable, filter(condition), last())

// or even simpler:

pipe(iterable, last(condition))

And if you want N last matching values:

pipe(iterable, filter(condition), takeLast(N))

forEach

Operator tap offers the same logic, to tap into each value, without changing the output.

join

Strings can be joined like this: aggregate(a => a.join(separator)), or you can define your own operator:

import {pipe, aggregate} from 'iter-ops';

function join(separator?: string) {
    return aggregate(a => a.join(separator));
}

We do not have a dedicated join operator, because operator aggregate makes it more generic and flexible, so you can have your own join operator that handles any type, and not just strings.

reverse

If the input is indexed (array-like), then the most efficient way is to use reverse helper on the source:

import {pipe, reverse} from 'iter-ops';

pipe(
    reverse(['word']), //=> Iterable<string> => 'd', 'r', 'o', 'w'
    // ...operators
)

Otherwise, the reversal is only possible on a complete dataset, so you have to aggregate the values first:

import {pipe, aggregate, spread} from 'iter-ops';

pipe(iterable,
     aggregate(arr => arr.reverse()), // aggregate and reverse the entire array
     spread() // spread the array
    );

slice

For arrays, slice(start, end) can take negative indexes, relative to the end of the array. This is not possible with iterators, which can only go from start till end.

However, for any combination of positive indexes, we can replicate the behavior:

const start = 3, end = 7; // start + end indexes

pipe(iterable, skip(start), take(end - start));

Border Values

  • To produce a min value from an iterable of numbers:
import {pipe, reduce} from 'iter-ops';

const input = [3, 0, -2, 5, 9, 4];

const i = pipe(input, reduce((p, c) => p < c ? p : c)); // IterableExt<number>

console.log(i.first); //=> -2
  • To produce a max value from an iterable of numbers:
import {pipe, reduce} from 'iter-ops';

const input = [3, 0, -2, 5, 9, 4];

const i = pipe(input, reduce((p, c) => p > c ? p : c)); // IterableExt<number>

console.log(i.first); //=> 9
  • To produce min + max values in a single iteration:
import {pipe, reduce} from 'iter-ops';

const input = [3, 0, -2, 5, 9, 4];

const i = pipe(input, reduce((p, c) => {
    p.min = c < p.min ? c : p.min ?? c;
    p.max = c > p.max ? c : p.max ?? c;
    return p;
}, {min: undefined as number, max: undefined as number}));
//=> IterableExt<{min: number, max: number}>

console.log(i.first); //=> { min: -2, max: 9 }

It will produce {min: undefined, max: undefined} when the input is empty.

  • To produce an average value from an iterable of numbers:
import {pipe, reduce} from 'iter-ops';

const input = [3, 0, -2, 5, 9, 4];

const i = pipe(input, reduce((p, c, idx, state) => {
    state.sum = (state.sum ?? p) + c;
    return p && state.sum / (idx + 1);
})); // IterableExt<number>

console.log(i.first); //=> 3.1666(6)

It will produce undefined when the input is empty.


See also: Custom Operators

Clone this wiki locally