- Starting a chain
- Transformation methods
- Ending a chain
.average()
.count()
.every(pred)
.find(pred)
.first()
.forEach(f)
.isEmpty()
.joinToString(separator)
.max(comparator?)
.min(comparator?)
.some(pred)
.sum()
.toArray()
.toMap(getKey, getValue)
.toMapGroupBy(getKey, transformer?)
.toObject(getKey, getValue)
.toObjectGroupBy(getKey, transformer?)
.toSet()
.toIterator()
.reduce(reducer, intialValue?)
- Iterables
- Utility functions
- Tree shakeable API
Starts a chain. Any number of transformation methods may be added, after which a termination method should be called to produce a result. No computation is done until a termination method is called.
The argument may be any iterable, such as an array, a string, or an ES6 Set
.
This is back-compatible with older browsers which did not implement the
Iterable
interface for arrays and strings.
Starts a chain for constructing a new transducer. Any number of transformation
methods may be added, after which .build()
should be called to produce a
transducer.
Any number of these methods may be called on a chain to add transformations in sequence.
Removes elements that are equal to the proceeding element (using ===
for
equality). For example:
chainFrom([1, 2, 2, 3, 3, 3])
.dedupe()
.toArray(); // -> [1, 2, 3]
Skips the first n
elements. If there are fewer than n
elements, then skip
all of them. If n
is negative, then leave the elements unchanged (same as
0
).
For example:
chainFrom([1, 2, 3, 4, 5])
.drop(3)
.toArray(); // -> [4, 5]
Skips elements as long as the predicate pred
holds. For example:
chainFrom([1, 2, 3, 4, 5])
.dropWhile(n => n < 3)
.toArray(); // -> [3, 4, 5]
Keeps only the elements matching the predicate pred
. For example:
chainFrom([1, 2, 3, 4])
.filter(x => x % 2 === 1)
.toArray(); // -> [1, 3]
For f
a function which maps each element to an iterable, applies f
to each
element and concatenates the results. For example:
const authors = [
{ name: "cbrontë", books: ["Jane Eyre", "Shirley"] },
{ name: "mshelley", books: ["Frankenstein"] },
];
chainFrom(authors)
.flatMap(author => author.books)
.toArray();
// -> ["Jane Eyre", "Shirley", "Frankenstein"]
For a chain of iterables, concatenates the contents of each iterable. For example:
chainFrom([[0, 1], [2], [], [3, 4]])
.flatten()
.toArray(); // [0, 1, 2, 3, 4]
Inserts separator
between each pair of elements. For example:
chainFrom([1, 2, 3, 4, 5])
.interpose(0)
.toArray();
// -> [1, 0, 2, 0, 3, 0, 4, 0, 5]
Transforms each element by applying f
to it. For example:
chainFrom([1, 2, 3])
.map(x => x * 2)
.toArray(); // -> [2, 4, 6]
Transforms each element by applying f
to the element and the current index in
the sequence. For example:
chainFrom(["a", "b", "c"])
.mapIndexed((x, i) => [x, i])
.toArray(); // -> [["a", 0], ["b", 1], ["c", 2]]
Groups elements into arrays of n
elements. If the number of elements does not
divide perfectly by n
, the last array will have fewer than n
elements.
Throws if n
is nonpositive. For example:
chainFrom([1, 2, 3, 4, 5])
.partitionAll(2)
.toArray();
// -> [[1, 2], [3, 4], [5]]
Groups consecutive elements for which f
returns the same value (as determined
by ===
) into arrays. For example:
chainFrom(["a", "ab", "bc", "c", "cd", "cde"])
.partitionBy(s => s[0])
.toArray();
// -> [["a", "ab"], ["bc"], ["c", "cd", "cde"]]
Like filter()
, but removes the elements matching pred
instead. For example:
chainFrom([1, 2, 3, 4])
.remove(x => x % 2 === 1)
.toArray(); // -> [2, 4]
Removes null
and undefined
elements (but not other falsy values). For
example:
chainFrom([0, 1, null, 2, undefined, 3])
.removeAbsent()
.toArray(); // -> [0, 1, 2, 3]
Takes the first n
elements and drops the rest. An essential operation for
efficiency, because it stops computations from occurring on more elements of the
input than needed to produce n
results. If there are less than n
elements,
then leave all of them unchanged. If n
is negative, then take none of them
(same as 0
). For example:
chainFrom([1, 2, 3, 4, 5])
.take(3)
.toArray(); // -> [1, 2, 3]
Takes every n
th element, starting from the first one. In other words, it takes
the elements whose indices are multiples of n
. Throws if n
is nonpositive.
For example:
chainFrom([1, 2, 3, 4, 5, 6])
.takeNth(2)
.toArray(); // [1, 3, 5]
Takes elements as long as the predicate pred
holds, then drops the rest. Like
take()
, stops unnecessary computations on elements after pred
fails. For
example:
chainFrom([1, 2, 3, 4, 5])
.takeWhile(n => n < 3)
.toArray(); // -> [1, 2]
Add an arbitrary transducer to the chain. transducer
should be a function
which implements the transducer
protocol,
meaning it is a function which takes a Transformer
and returns another
Transformer
. This is the most general transformation, and it is used by this
library internally to implement all the others. For example usage, see the
Using custom
transducers
section of the main readme.
The following methods terminate a chain started with chainFrom
, performing the
calculations and producing a result.
For a chain of numbers, return their average, or null
if there are no
elements. For example:
chainFrom(["a", "bb", "ccc"])
.map(s => s.length)
.average(); // -> 2
Returns the number of elements. For example:
chainFrom([1, 2, 3, 4, 5])
.filter(x => x % 2 === 1)
.count(); // -> 3
Returns true
if all elements satisfy the predicate pred
, or false
otherwise. Short-circuits computation once a failure is found. Note that this is
equivalent to .remove(pred).isEmpty()
.
Example:
chainFrom([1, 2, 3, 4, 5])
.map(n => 10 * n)
.every(n => n > 3); // -> true
chainFrom([1, 2, 3, 4, 5])
.map(n => 10 * n)
.every(n => n < 30); // -> false
Returns the first element of the result which satisfies the predicate pred
, or
null
if no such element exists. Short-circuits computation once a match is
found. Note that this is equivalent to .filter(pred).first()
.
Example:
chainFrom([1, 2, 3, 4, 5])
.map(x => x * 10)
.find(x => x % 6 === 0); // -> 30
Returns the first element of the result, or null
if there are no elements.
Short-circuits computation after reading the first element.
Example:
chainFrom([1, 2, 3, 4, 5])
.map(x => x * 10)
.first(); // -> 10
Calls f
on each element of the result, presumably for side-effects. For
example:
chainFrom([1, 2, 3, 4, 5])
.map(x => x * 10)
.forEach(x => console.log(x));
// Prints 10, 20, 30, 40, 50
Returns true
if there are any elements, else false
. Short-circuits
computation after reading one element. For example:
chainFrom([1, 2, 3, 4, 5])
.filter(n => n > 10)
.isEmpty(); // -> true
chainFrom([1, 2, 3, 4, 5])
.filter(n => n % 2 === 0)
.isEmpty(); // -> false
Returns a string obtained by concatenating the elements together as strings with the separator between them. For example:
chainFrom([1, 2, 3, 4, 5])
.filter(n => n % 2 === 1)
.joinToString(" -> "); // -> "1 -> 3 -> 5"
Not called toString()
in order to avoid clashing with the Object
prototype
method.
Returns the maximum element, according to the comparator. If the elements are
numbers, then this may be called without providing a comparator, in which case
the natural comparator is used. Returns null
if there are no elements.
Example:
chainFrom(["a", "bb", "ccc"])
.map(s => s.length)
.max(); // -> 3
Returns the minimum element, according to the comparator. If the elements are
numbers, then this may be called without providing a comparator, in which case
the natural comparator is used. Returns null
if there are no elements.
Example:
chainFrom(["a", "bb", "ccc"])
.map(s => s.length)
.min()); // -> 1
Returns true
if any element satisfies the predicate pred
, or false
otherwise. Short-circuits computation once a match is found. Note that this is
equivalent to .filter(pred).isEmpty() === false
.
Example:
chainFrom([1, 2, 3, 4, 5])
.map(n => 10 * n)
.some(n => n === 30); // -> true
chainFrom([1, 2, 3, 4, 5])
.map(n => 10 * n)
.some(n => n === 1); // -> false
For a chain of numbers, return their sum. If the input is empty, return 0
. For
example:
chainFrom(["a", "bb", "ccc"])
.map(s => s.length)
.sum(); // -> 6
Returns an array of the results. See any of the above examples.
Returns an ES6 Map
, each of whose key-value pairs is generated by calling the
provided funtions on each element in the result. If multiple elements produce
the same key, then the value produced by the latest element will override the
earlier ones. Similar to .toObject()
, except that
the getKey
function is permitted to return any type of value, not just a
string.
This function assumes that Map
is present in your environment. If you call
this function, you are responsible for providing a polyfill if your environment
does not natively support Map
.
Example:
const authors = [
{ name: "cbrontë", books: ["Jane Eyre", "Shirley"] },
{ name: "mshelley", books: ["Frankenstein"] },
];
chainFrom(authors).toMap(
a => a.id,
a => a.books.length,
);
// -> Map{ "cbrontë" -> 2, "mshelley" -> 4 }
Produces an ES6 Map
by grouping together all elements for which getKey
returns the same value under that key. By default, each key corresponds to an
array of the elements which produced that key.
Optionally, a transformer may be passed as the second argument to configure the
reduction behavior of the values. All chain-ending methods in this section other
than .toIterator()
have a standalone variant which produces a transformer (for
details, see the section Tree shakeable API), which opens
many possibilities. Some advanced examples are shown below.
Similar to .toObjectGroupBy()
, except
that the getKey
function is permitted to return any type of value, not just a
string.
This function assumes that Map
is present in your environment. If you call
this function, you are responsible for providing a polyfill if your environment
does not natively support Map
.
Examples:
chainFrom(["a", "b", "aa", "aaa", "bc"]).toMapGroupBy(s => s[0]);
// -> Map{ "a" -> ["a", "aa", "aaa"], "b" -> ["b", "bc"] }
chainFrom(["a", "b", "aa", "aaa", "bc"]).toMapGroupBy(s => s[0], count());
// -> Map{ "a" -> 3, "b" -> 2 }
chainFrom(["a", "b", "aa", "aaa", "bc"]).toMapGroupBy(
s => s[0],
some(s => s.length === 3),
);
// -> Map{ "a" -> true, "b" -> false }
chainFrom(["a", "b", "aa", "aaa", "bc"]).toMapGroupBy(
s => s[0],
map((s: string) => s.length)(toAverage()),
);
// -> Map{ "a" -> 2, "b" -> 1.5 }
Returns an object, each of whose key-value pairs is generated by calling the
provided functions on each element in the result. If multiple elements produce
the same key, then the value produced by the latest element will override the
earlier ones. Similar to .toMap()
, except that the
getKey
function is required to return a string.
Example:
const authors = [
{ name: "cbrontë", books: ["Jane Eyre", "Shirley"] },
{ name: "mshelley", books: ["Frankenstein"] },
];
chainFrom(authors).toObject(
a => a.id,
a => a.books.length,
);
// -> { cbrontë: 2, mshelley: 1 }
Produces an object by grouping together all elements for which getKey
returns
the same value under that key. By default, each key corresponds to an array of
the elements which produced that key.
Optionally, a transformer may be passed as the second argument to configure the
reduction behavior of the values. All chain-ending methods in this section other
than .toIterator()
have a standalone variant which produces a transformer (for
details, see the section Tree-shakeable API), which opens
many possibilities. Some advanced examples are shown below.
Similar to .toMapGroupBy()
, except that the
getKey
function is required to return a string.
Examples:
chainFrom(["a", "b", "aa", "aaa", "bc"]).toObjectGroupBy(s => s[0]);
// -> { a: ["a", "aa", "aaa"], b: ["b", "bc"] }
chainFrom(["a", "b", "aa", "aaa", "bc"]).toObjectGroupBy(s => s[0], count());
// -> { a: 3, b: 2 }
chainFrom(["a", "b", "aa", "aaa", "bc"]).toObjectGroupBy(
s => s[0],
some(s => s.length === 3),
);
// -> { a: true, b: false }
chainFrom(["a", "b", "aa", "aaa", "bc"]).toMapGroupBy(
s => s[0],
map((s: string) => s.length)(toAverage()),
);
// -> { a: 2, b: 1.5 }
Returns an ES6 Set
of the results.
This function assumes that Set
is present in your environment. If you call
this function, you are responsible for providing a polyfill if your environment
does not natively support Set
.
Returns an iterator. Elements of the input iterator are not read until this iterator is read, and then only as many as needed to compute the number of results requested. This is the primary way of reading results lazily.
Example:
const iterator = chainFrom([1, 2, 3, 4, 5])
.map(x => x * 10)
.toIterator();
console.log(iterator.next().value()); // Prints 10
// So far, the map function has only been called once.
Reduces the elements according to the reducer, and returns the result. reducer
may be either a plain function of the form (acc, x) => acc
or a transformer as
defined by the transformer
protocol.
This is the most general way to terminate a chain, and all the others (except
for toIterator
) are implemented using it.
Example of using a plain function reducer:
chainFrom([1, 2, 3, 4, 5])
.map(x => x * 10)
.reduce((acc, x) => acc + x, 0); // -> 150
A handful of pre-made transformers are provided by this library to be used with
reduce()
. They are described in the next section.
Helper functions for producing iterables, often useful for starting chains.
Returns an iterable which repeats the elements of the input iterable indefinitely. If the input iterable is empty, then produces an empty iterable. For example:
chainFrom(cycle(["a", "b", "c"]))
.take(7)
.toArray(); // -> ["a", "b", "c", "a", "b", "c", "a"]
chainFrom(cycle([])).toArray(); // -> []
Returns an iterable which emits initialValue
, f(initialValue)
,
f(f(initialValue))
, and so on. For example:
chainFrom(iterate(1, x => 2 * x))
.take(5)
.toArray(); // -> [1, 2, 4, 8, 16]
Returns an iterable which emits value
repeatedly. If count
is provided, then
emits value
that many times. If count
is omitted, then emits value
indefinitely. Throws if count
is negative. For example:
chainFrom(repeat("x"))
.take(3)
.toArray(); // -> ["x", "x", "x"]
chainFrom(repeat("x", 3)).toArray(); // -> ["x", "x", "x"]
Returns an iterable which outputs values from start
inclusive to end
exclusive, incrementing by step
each time. start
and step
may be omitted,
and default to 0
and 1
respectively.
If step is positive, then outputs values incrementing upwards from start
until
the last value less than end
. If step is negative, then outputs values
incrementing downwards from start
until the last value greater than end
.
A start
greater than or equal to end
for positive step
, or a start
less
than or equal to end
for a negative step
, is permitted, and produces an
empty iterator.
Throws an error if step
is zero.
Example:
chainFrom(range(3))
.map(i => "String #" + i)
.toArray(); // -> ["String #0", "String #1", "String #2"]
chainFrom(range(10, 15)).toArray(); // -> [10, 11, 12, 13, 14]
chainFrom(range(10, 15, 2)).toArray(); // -> [10, 12, 14]
chainFrom(range(15, 10, -2)).toArray(); // -> [15, 13, 11]
Values are produced lazily, so for example the following will return quickly and not use up all your memory:
chainFrom(range(1000000000000))
.take(3)
.toArray(); // -> [0, 1, 2]
Returns true if result
is a reduced value as described by the transducer
protocol.
Returns a reduced value of result
, as described by the transducer
protocol. Can be
returned by a reducer or a transformer to short-circuit computation.
As discussed in the readme section Bundle Size and Tree
Shaking,
Transducist also provides standalone functions with the same behavior as the
chain, for the purposes of reducing bundle size. In particular, all chain
methods (except toIterator()
) have a standalone function of the same name.
For those familiar with the transducer
protocol,
the standalone functions corresponding to the transform methods (e.g. map()
,
take()
) each produce a transducer, while the standalone functions
corresponding to the end of the chain (e.g. toArray()
, count()
) each produce
a transformer.
In addition to the standalone functions whose names match the methods listed above, the tree-shakeable API is completed by the functions below.
Composes any number of transducers together to produce a new transducer. This is actually just ordinary function composition, although its TypeScript typings are specialized for transducers in particular.
(Or: transduce(iterable, transducer, reducer, initialValue)
)
Starting from the iterable, applies the transformations specified by the transducer and then uses the transformer to construct a final result.
Rather than providing a transformer as the third argument, this may also be
called by passing an ordinary reducer function and an initial value as the final
two arguments, where a reducer is a plain function of the form (acc, x) => acc
.
Example:
import { compose, filter, map, toArray, transduce } from "transducist";
transduce(
[1, 2, 3, 4, 5],
compose(
filter(x => x > 2),
map(x => 2 * x),
),
toArray(),
); // -> [6, 8, 10]
which is equivalent to the chained version:
import { chainFrom } from "transducist";
chainFrom([1, 2, 3, 4, 5])
.filter(x => x > 2)
.map(x => 2 * x)
.toArray(); // -> [6, 8, 10]
Returns an iterator which lazily performs the transformations specified by the
transducer. This is the standalone version of ending a chain with
.toIterator()
. That is, the following are equivalent:
import { compose, filter, map, lazyTransduce } from "transducist";
lazyTransduce(
[1, 2, 3, 4, 5],
compose(
filter(x => x > 2),
map(x => 2 * x),
),
);
import { chainFrom } from "transducist";
chainFrom([1, 2, 3, 4, 5])
.filter(x => x > 2)
.map(x => 2 * x)
.toIterator();
Copyright © 2017 David Philipson