Generic library for advanced utilization of es6 iterators.
map, fold and so on...
sequence.js functions are fully lazy and work with anything implementing the iterator protocol; in addition, all functions also support treating plain objects as sequences!
The advantage of lazy implementations is that these functions work efficiently
with very long or even infinite sequences; assuming the following example is
given a sequence with ten billion elements, it would still start printing it's
output immediately and would not require creating another billion element array
as Array.map
would do.
In practice the x*2
would be calculated immediately before the result is printed.
each(map(sequence, (x) => x*2), console.log)
A disadvantage of lazyness is that side effects (e.g. a console.log inside a map()) are not executed, before the resulting sequence is actually being consumed by a for loop or each() or fold() or similar functions… So if you need to perform side effects, remember to use one of these instead of lazy functions like map();
sequence.js functions also support passing functions as the last argument:
each(seq, (elm) => {
doSomething(elm);
console.log(elm);
});
is much more readable then the example below; especially when you are using multiple nested each/map/fold calls and the function bodies grow long!
each((elm) => {
doSomething(elm);
console.log(elm);
}, seq);
Some of the utilities in here can mostly be implemented with standard js6. The emphasis here is on mostly, since sequence.js functions are designed to have fewer edge cases that classical es6 pendants and therefor make for a smoother coding experience.
Examples:
Iteration
> for (const v of {foo: 42, bar: 23}) console.log(v);
TypeError: {(intermediate value)(intermediate value)} is not iterable
Does not work because plain objects do not implement the iterator protocol.
Replace With
> each([1,2,3,4], console.log);
1
2
3
4
or
> each({foo: 42}, v => console.log(v));
[ 'foo', 42 ]
or the following if the full power of a for loop is really required..
for (const v of iter({foo: 42})) console.log(v);
[ 'foo', 42 ]
Array.forEach
> [1,2,3,4].forEach(console.log)
1 0 [ 1, 2, 3, 4 ]
2 1 [ 1, 2, 3, 4 ]
3 2 [ 1, 2, 3, 4 ]
4 3 [ 1, 2, 3, 4 ]
Unexpectedly yields a lot of output; that is because forEach also passes
the index in the array as well as the thisArgument
.
This behaviour is often unexpected and forces us to define an intermediate
function.
Replace With
> each([1,2,3,4], console.log);
1
2
3
4
If the index is really needed, enumerate()
may be used:
each(enumerate([42, 23]), console.log)
[ 0, 42 ]
[ 1, 23 ]
As a sidenote this also effortlessly fits the concept of a key/value
container; the output of enumerate([42, 23])
could easily passed
into new Map(...)
;
The full behaviour of for each
 Source:
Interfaces
Members
(inner, constant) extend
 Source:
Generate a sequence by repeatedly calling the same function on the previous value.
This is often used in conjunction with takeDef or takeWhile to generate a noninfinite sequence.
// Generate an infinite list of all positive integers
extend(0, x => x+1);
// Generate the range of integers [first; last[
const range = (first, last) =>
takeUntilVal(extend(first, x => x+1), last);
(inner, constant) extend1
 Source:
Like extend(), but the resulting sequence does not contain the initial element.
(inner, constant) flattenTree
 Source:
Flatten trees of any type into a sequence.
The given function basically has three jobs:
 Decide whether a given value in a tree is a node or a leaf (or both)
 Convert nodes into sequences so we can easily recurse into them
 Extract values from leaves
If the given function does it's job correctly, visit will yield a sequence with all the values from the tree.
The function must return a sequence of values! It is given the current node as well as a callback that that takes a list of child nodes and flattens the given subnodes.
Use the following return values:
flattenTree((node, recurse) => {
if (isEmptyLeaf()) {
return [];
} else if (isLeaf(node)) {
return [node.value];
} else if (isMultiLeaf(node)) {
return node.values;
} else if (isNode(node)) {
return recurse(node.childNodes);
} else if (isLeafAndNode(node)) {
return concat([node.value], recurse(node.childNodes));
}
}
});
(inner, constant) join
 Source:
Convert each element from a sequence into a string and join them with the given separator.
(inner, constant) into
 Source:
Convert values into a given type using the Into
trait.
Note that this has inverse parameters compared to the trait
(sequence first, type second) for currying purposes.
(inner, constant) foldl
 Source:
Combine all the values from a sequence into one value.
This function is also often called reduce, because it reduces multiple values into a single value.
Here are some common use cases of the foldl function:
const all = (seq) => foldl(seq, true, (a, b) => a && b);
const any = (seq) => foldl(seq, false, (a, b) => a  b);
const sum = (seq) => foldl(seq, 0, (a, b) => a + b);
const product = (seq) => foldl(seq, 1, (a, b) => a * b);
Notice the pattern: We basically take an operator and apply
it until the sequence is empty: sum([1,2,3,4]) is pretty much
equivalent to 1 + 2 + 3 + 4
.
(If you want to get very mathematical here...notice how we basically have an operation and then just take the operation's neutral element as the initial value?)
(inner, constant) foldr
 Source:
Like foldl, but righttoleft
(inner, constant) map
 Source:
Lazily transform all the values in a sequence.
into(map([1,2,3,4], n => n*2), Array) # [2,4,6,8]
(inner, constant) filter
 Source:
Remove values from the sequence based on the given condition.
filter(range(0,10), x => x%2 == 0) // [2,4,6,8]
(inner, constant) reject
 Source:
Opposite of filter: Removes values from the sequence if the function returns true.
(inner, constant) trySkip
 Source:
Like skip, but returns an exhausted iterator if the sequence contains
less than no
elements instead of throwing IteratorEnded.
(inner, constant) skip
 Source:
Skip elements in a sequence.
Throws IteratorEnded if the sequence contains less than no
elements.
(inner, constant) skipWhile
 Source:
Skips elements in the given sequences until one is found for which the predicate is false.
(inner, constant) tryTake
 Source:
Yields an iterator of the first no
elements in the given
sequence; the resulting iterator may contain less then no
elements if the input sequence was shorter than no
elements.
(inner, constant) take
 Source:
Version of tryTake that will throw IteratorEnded if the given iterable is too short.
(inner, constant) takeWhile
 Source:
Cut off the sequence at the first point where the given condition is no longer met.
list(takeWhile([1,2,3,4,5,6...], x => x < 4))
yields [1,2,3]
(inner, constant) takeUntilVal
 Source:
Cut of the sequence at the point where the given value is first encountered.
(inner, constant) prepend
 Source:
Given a sequence and a value, prepend the value to the sequence, yielding a new iterator.
(inner, constant) append
 Source:
Given a sequence and a value, append the value to the sequence, yielding a new iterator.
(inner, constant) mapSort
 Source:
Sort a sequence. The given function must turn map each parameter to a string or number. Objects will be sorted based on those numbers.A If the given parameters are already numbers/strings, you may just use identity as the mapping function.
(inner, constant) zipLeast2
 Source:
Curryable version of zipLeast
(inner, constant) zip2
 Source:
Curryable version of zip
(inner, constant) zipLongest
 Source:
Zip multiple sequences. Puts all the first values from sequences into one sublist; all the second values, third values and so on... If the sequences are of different length, the resulting iterator will have the length of the longest sequence; the missing values from the shorter sequences will be substituted with the given fallback value.
(inner, constant) zipLongest2
 Source:
Curryable version of zipLongest
(inner, constant) slidingWindow
 Source:
Forms a sliding window on the underlying iterator.
slidingWindow([1,2,3,4,5], 3)
yields [[1,2,3], [2,3,4], [3,4,5]]
Will throw IteratorEnded if the sequence is shorter than the given window.
(inner, constant) trySlidingWindow
 Source:
Like slidingWindow, but returns an empty sequence if the given sequence is too short.
(inner, constant) lookahead
 Source:
Almost like trySlidingWindow, but makes sure that every element from the sequence gets it's own subarray, even the last element. The arrays at the end are filled with the filler value to make sure they have the correct length.
lookahead([], 3, null) # => []
lookahead([42], 3, null) # => [[42, null, null, null]]
lookahead([42, 23], 3, null) # => [[42, 23, null, null], [23, null, null, null]]
lookahead([42, 23], 0, null) # => [[42], [23]]
Try sliding window would yield an empty array in each of the examples above.
(inner, constant) mod
 Source:
Modify/Transform the given value.
Applys the given value to the given function; after the return value is known, that return value is converted into the type of the given parameter.
const s = new Set([1,2,3,4]);
const z = mod1(s, map(plus(1))); # => new Set([2,3,4,5]),
assert(z.constructor === Set)
(inner, constant) union2
 Source:
Curryable version of union
Methods
(inner) iter(obj)
 Source:
Turn any object into an iterator. Takes objects that implement the iterator protocol. Plain objects are treated as keyvalue stores and yield a sequence of their key value bytes, represented as size2 arrays.
Any value that is allowed as a parameter for this function shall be
considered to be a Sequence
for the purpose of this file.
This term shall be distinguished from Iterable
in that iterables
must implement the iterator protocol iterable[Symbol.iterator]()
.
Version history
 1.2.0 Support for objects with Symbol keys.
Parameters:
Name  Type  Description 

obj 
Object  Iterable  Iterator 
Returns:
 Type
 Iterator
Yields:
(generator, inner) range(start, start)
 Source:
Generates an iterator with the numeric range [start; end[ Includes start but not end.
Parameters:
Name  Type  Description 

start 
Number  
start 
Number 
(inner) range0()
 Source:
Like range(a, b) but always starts at 0
(generator, inner) repeat()
 Source:
Generates an infinite iterator of the given value.
(inner) next(seq) → {Any}
 Source:
Extracts the next element from the iterator.
const {iter, next} = require('ferrum');
const it = iter([1,2,3]);
next(it); // => 1
next(it); // => 2
next(it); // => 3
next(it); // throws IteratorEnded
next(it); // throws IteratorEnded
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
Throws:

If the sequence is empty
 Type
 IteratorEnded
Returns:
 Type
 Any
(inner) tryNext(seq, fallback) → {Any}
 Source:
Extracts the next element from the iterator.
const {iter, tryNext} = require('ferrum');
const it = iter([1,2,3]);
tryNext(it, null); // => 1
tryNext(it, null); // => 2
tryNext(it, null); // => 3
tryNext(it, null); // => null
tryNext(it, null); // => null
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
fallback 
Any  The value to return if the sequence is empty 
Returns:
 Type
 Any
(inner) nth(seq, idx) → {Any}
 Source:
Extract the nth element from the sequence
const {iter, next, nth} = require('ferrum');
const it = iter('hello world');
nth(it, 3); // => 'l'
next(it); // => 'o'
const fifth = nth(4);
fifth(it) // => 'l'
nth(it, 10); // throws IteratorEnded
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
idx 
Number  The index of the element 
Throws:

If the sequence is too short
 Type
 IteratorEnded
Returns:
 Type
 Any
(inner) first(seq) → {Any}
 Source:
Extract the first element from the sequence; this is effectively an alias for next();
const {first} = require('ferrum');
first([1,2]) // => 1
first([]); // throws IteratorEnded
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
Throws:

If the sequence is too short
 Type
 IteratorEnded
Returns:
 Type
 Any
(inner) second(seq) → {Any}
 Source:
Extract the second element from the sequence
const {second} = require('ferrum');
second([1,2]) // => 2
second([1]); // throws IteratorEnded
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
Throws:

If the sequence is too short
 Type
 IteratorEnded
Returns:
 Type
 Any
(inner) last(seq) → {Any}
 Source:
Extract the last element from the sequence
const {last} = require('ferrum');
last([1,2,3,4,5]) // => 5
last([]); // throws IteratorEnded
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
Throws:

If the sequence is empty
 Type
 IteratorEnded
Returns:
 Type
 Any
(inner) tryNth(seq, idx, fallback) → {Any}
 Source:
Extract the nth element from the sequence
const {iter, next, tryNth} = require('ferrum');
const it = iter('hello world');
tryNth(it, null, 3); // => 'l'
next(it); // => 'o'
const fifth = nth(4, null);
fifth(it) // => 'l'
tryNth(it, 10, null); // => null
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
idx 
Number  The index of the element 
fallback 
Any  The value to return if the sequence is too short 
Returns:
 Type
 Any
(inner) tryFirst(seq, fallback) → {Any}
 Source:
Extract the first element from the sequence; this is effectively an alias for tryNext();
const {tryFirst} = require('ferrum');
tryFirst([1,2], null) // => 1
tryFirst([], null); // => null
const fn = tryFirst(null);
fn([]); // => null
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
fallback 
Any  The value to return if the sequence is too short 
Returns:
 Type
 Any
(inner) trySecond(seq, fallback) → {Any}
 Source:
Extract the second element from the sequence
const {trySecond} = require('ferrum');
trySecond([1,2], null) // => 2
trySecond([1], null); // => null
const fn = trySecond(null);
fn([1]); // => null
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
fallback 
Any  The value to return if the sequence is too short 
Returns:
 Type
 Any
(inner) tryLast(seq, fallback) → {Any}
 Source:
Extract the last element from the sequence
const {tryLast} = require('ferrum');
tryLast([1,2,3,4,5], null) // => 5
tryLast([], null); // => null
const fn = tryLast(null);
fn([]); // => null
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
fallback 
Any  The value to return if the sequence is empty 
Returns:
 Type
 Any
(inner) each(seq, fn)
 Source:
Iterate over sequences: Apply the give function to every element in the sequence
const {each} = require('ferrum');
each({foo: 42, bar: 23}, ([key, value]) => {
console.log(`${key}: ${value}`)
});
each([1,2,3], (v) => {
console.log(v);
});
Version history
 1.2.0 Support for objects with Symbol keys.
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
fn 
function  Function taking a single parameter 
(inner) find(seq, fn)
 Source:
Return the first element in the sequence for which the predicate matches.
const {find} = require('ferrum');
find([1,2,3,4], v => v>2); // => 3
find([1,2,3,4], v => v>10); // throws IteratorEnded
const findEven = find(v => v % 2 === 0);
find([3,4,1,2]); // => 4
find([]); // throws IteratorEnded
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
fn 
function  The predicate 
Throws:

If no element in the sequence matches the predicate..
 Type
 IteratorEnded
Returns:
Any
(inner) tryFind(seq, fallback, fn)
 Source:
Return the first element in the sequence for which the predicate matches.
const {tryFind} = require('ferrum');
tryFind([1,2,3,4], null, v => v>2); // => 3
tryFind([1,2,3,4], null, v => v>10); // => null
const findEven = tryFind(null, v => v%2 === 0);
findEven([1,9,10,14]); // => 10
findEven([]); // => null
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
fallback 
Any  The value to return if no element in the sequence matches the predicate 
fn 
function  The predicate 
Returns:
Any
(inner) contains(seq) → {Boolean}
 Source:
Test if the given sequence contains a value that matches the predicate.
const {contains, eq, is, not} = require('ferrum');
const containsEven = contains(x => x%2 === 0);#
containsEven([1,2,3,4]); // => true
containsEven([1,3,5,7]); // => false
// Use is to search vor values using the === operator
const contains4 = contains(is(4));
// const contains4 = contains(x => x === 4); // this is a bit longer & harder to read
contains4([1,2,3]); // => false
contains4([4,4,4]); // => true
// You can use eq to search for values equal to another value
const containsEmptyObject = contains(eq({}));
containsEmptyObject([{foo: 42}]); // => false
containsEmptyObject([{}]); // => true
This function should be used over tryFind
in cases where just the presence
of a value should be tested for:
// The usual pattern checking whether a value is contained would be this:
tryFind([1,2,3,4], null, is(3)); // => 3 (truthy)
tryFind([1,2,4,5], null, is(3)); // => null (falsy)
// Obviously this pattern breaks down when searching for falsy values
tryFind([0,1,2,3,4], null, is(0)); // => 0 (falsy  FALSE POSITIVE)
tryFind([1,1,2,3,4], null, is(0)); // => null (falsy)
// Using contains() gets you around this issue and does what you would expect
contains([0,1,2,3,4], is(0)); // => true
contains([1,1,2,3,4], is(0)); // => false
// If you need to search for the value and do not want to run into this issue,
// the following pattern (creating a symbol on the fly) can be used
// This is also how contains() is implemented.
// You could also use null or undefined as the sentinel value, but this is discouraged,
// as the sequence could contain those values; this can never be the case with a symbol
// you just created
const nothing = Symbol('');
const v = tryFind([1,2,3,null,4,0], nothing, not) // tryFindFalsy
if (v === nothing) {
// handle that case
} else {
// Got a valid, falsy value
}
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
Returns:
 Type
 Boolean
(inner) seqEq(a, b) → {Boolean}
 Source:
Determine whether the items in two sequences are equal.
const {seqEq, eq} = require('ferrum');
seqEq([1,2,3,4], [1,2,3,4]); // => true
seqEq([1,2,3,4], [1,2,3]); // => false
// The types of the objects being compared is not important,
// just the contents of the iterator
seqEq(new Set([1,2,3]), [1,2,3]); // => true
seqEq(new Set([1,2,3,3]), [1,2,3,3]); // => false (the set discards the second 3)
// Note that sets and maps should usually compared using eq() and not
// seqEq, since seqEq cares about the infestation order while eq() does
// not for sets and maps
eq(new Set([1,2,3]), new Set([1,2,3])); // => true
eq(new Set([3,2,1]), new Set([1,2,3])); // => true
seqEq(new Set([1,2,3]), new Set([1,2,3])); // => true
seqEq(new Set([3,2,1]), new Set([1,2,3])); // => false
// Objects should never be compared using seqEq, because the order
// in which the elements of an object are returned is undefined
const obj = {foo: 23, bar: 42};
seqEq(obj, obj); // UNDEFINED BEHAVIOUR; could be true or false
// Same goes of course for es6 Maps created from objects
seqEq(dict(obj), dict(obj))); // => UNDEFINED BEHAVIOUR; could be true or false
// Objects as elements inside the iterator are OK; elements are compared
// using eq() not seqEq()
seqEq([{foo: 42, bar: 23}], [{bar: 23, foo: 42}]); // => true
Parameters:
Name  Type  Description 

a 
Sequence  Any sequence for which iter() is defined 
b 
Sequence  Any sequence for which iter() is defined 
Returns:
 Type
 Boolean
(inner) assertSequenceEquals(a, b, msg) → {Boolean}
 Source:
Assert that two finite sequences are equals.
Parameters:
Name  Type  Description 

a 
Sequence  Any sequence for which iter() is defined 
b 
Sequence  Any sequence for which iter() is defined 
msg 
String  undefined  The error message to print 
Throws:
Returns:
 Type
 Boolean
(inner) count(a) → {Number}
 Source:
Determine the number of elements in an iterator. This will try using trySize(), but fall back to iterating over the container and counting the elements this way if necessary.
const {iter,count} = require('ferrum')
count([1,2,3]); // => 3; O(1)
count(iter([1,2,3])); // => 3; O(n)
Parameters:
Name  Type  Description 

a 
Sequence  Any sequence for which iter() is defined 
Returns:
 Type
 Number
(inner) list()
 Source:
Turns any sequence into a list.
Shorthand for Array.from(iter())
.
This is often utilized to cache a sequence so it can be
iterated over multiple times.
(inner) uniq()
 Source:
Turns any sequence into a set. Shorthand for new Set(iter()). This often finds practical usage as a way of removing duplicates elements from a sequence.
(inner) dict()
 Source:
Turns any sequence into an es6 map This is particularly useful for constructing es7 maps from objects...
(inner) obj()
 Source:
Turns any sequence into an object
(inner) any()
 Source:
Test whether any element in the given sequence is truthy. Returns null if the list is empty.
(inner) all()
 Source:
Test whether all elements in the given sequence are truthy Returns true if the list is empty.
(inner) sum()
 Source:
Calculate the sum of a list of numbers. Returns 0 is the list is empty.
(inner) product()
 Source:
Calculate the product of a list of numbers. Returns 1 is the list is empty.
(inner) reverse(seq) → {Array}
 Source:
Reverse a given sequence
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
Returns:
 Type
 Array
(generator, inner) enumerate(seq) → {Iterator}
 Source:
Extend the given sequences with indexes: Takes a sequence of values and generates a sequence where each element is a pair [index, element];
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
Returns:
 Type
 Iterator
(inner) takeDef(seq) → {Iterator}
 Source:
Cut of the given sequence at the first undefined or null value.
Parameters:
Name  Type  Description 

seq 
Sequence  Any sequence for which iter() is defined 
Returns:
 Type
 Iterator
(generator, inner) flat(seq)
 Source:
Flattens a sequence of sequences.
into(flat([[1,2], [3,4]]), Array) # [1,2,3,4]
into(flat({foo: 42}), Array) # ["foo", 42]
Parameters:
Name  Type  Description 

seq 
Sequence(Sequence)  Any sequence for which iter() is defined 
(inner) concat()
 Source:
Concatenate any number of sequences.
This is just a variadic alias for flat()
(inner) zipLeast(seq) → {Iterator}
 Source:
Zip multiple sequences. Puts all the first values from sequences into one sublist; all the second values, third values and so on. If the sequences are of different length, the output sequence will be the length of the shortest sequence and discard all remaining from the longer sequences...
Parameters:
Name  Type  Description 

seq 
Sequence  A sequence of sequences 
Returns:
 Type
 Iterator
(generator, inner) zip(seq) → {Iterator}
 Source:
Zip multiple sequences. Puts all the first values from sequences into one sublist; all the second values, third values and so on. If the sequences are of different length, an error will be thrown.
Parameters:
Name  Type  Description 

seq 
Sequence  A sequence of sequences 
Returns:
 Type
 Iterator
(generator, inner) cartesian(seqs) → {Array}
 Source:
Calculate the cartesian product of the given sequences.
const {cartesian, list} = require('ferrum');
list(cartesian([])); // => []
list(cartesian([[1,2]])); // => [[1], [2]]
list(cartesian([[1,2], [3,4]])); // => [[1,3], [1, 4], [2, 3], [2, 4]]
list(cartesian([[1,2], [3,4], [5,6]]));
// => [[1,3,5], [1,3,6], [1,4,5], [1,4,6],
[2,3,5], [2,3,6], [2,4,5], [2,4,6]]
list(cartesian([[], [3,4], [5,6]])); // => []
Parameters:
Name  Type  Description 

seqs 
Sequence  A sequence of sequences 
Yields:
 Type
 Array
(inner) union()
 Source:
Combine multiple map/set like objects.
The return type is always the type of the first value. Internally this just concatenates the values from all parameters and then uses into to convert the values back to the original type.
union({a: 42, b: 23}, new Map([['b', 99]]))
=> {a: 42, b: 99}
union(new Set(1,2,3,4), [4,6,99])
=> new Set([1,2,3,4,6,99])
AA
Takes any number of values to combine.