iter.mjs provides tiny utils for iteration and functional programming. Lightweight replacement for Lodash. Features:
- Higher-order functions for data structures.
- Common FP tools like
map,filter, and many more. - Compatible with arbitrary iterables such as lists, sets, maps, dicts.
- Common FP tools like
Differences from Lodash:
- Supports arbitrary iterables and iterators, including sets and maps.
- Much smaller and simpler.
Port and rework of https://github.com/mitranim/fpx.
- #Usage
- #Perf
- #API
- #
function arrOf - #
function more - #
function alloc - #
function arr - #
function arrCopy - #
function slice - #
function keys - #
function values - #
function valuesCopy - #
function entries - #
function reify - #
function indexOf - #
function findIndex - #
function includes - #
function append - #
function prepend - #
function concat - #
function len - #
function hasLen - #
function each - #
function map - #
function mapMut - #
function mapCls - #
function mapCompact - #
function mapFlat - #
function filter - #
function reject - #
function compact - #
function remove - #
function fold - #
function fold1 - #
function find - #
function procure - #
function every - #
function some - #
function flat - #
function head - #
function last - #
function init - #
function tail - #
function take - #
function count - #
function compare - #
function compareFin - #
function sort - #
function reverse - #
function index - #
function group - #
function partition - #
function sum - #
function zip - #
function range - #
function span - #
function times - #
function repeat - #
function mapDict - #
function pick - #
function omit - #
function pickKeys - #
function omitKeys - #Undocumented
- #
import * as i from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/iter.mjs'Carefully tuned for performance. Functions covered by benchmarks appear comparable to their native or Lodash equivalents. Many appear significantly faster.
JS performance is complicated and very unstable, Our benchmark suite is limited and checked only in V8. When in doubt, measure in your particular environment.
Links: source; test/example.
Signature: (seq<A>, test) => A[] where test: A => true.
Shortcut. Converts the input to an array via #arr and asserts that every element satisfies the given test function. Returns the resulting array.
Links: source; test/example.
Takes an i, consumes one value, and returns true if the iterator is not yet finished. Shortcut for val.next().done === false.
Links: source; test/example.
Shortcut for allocating an array with a sanity check. Same as Array(N) but ensures that the input is a n suitable for array length. Avoids unintentionally passing any non-natural input such as Array(-1). Allows n, replacing it with 0.
Links: source; test/example.
Converts an arbitrary s to an array. Supports the following inputs:
- N: return
[]. - A: return as-is.
- L: convert via
Array.prototype.slice. - S or arbitrary i: convert to array by iterating.
Unlike #values, this function rejects other inputs such as non-nil primitives, dicts, maps, arbitrary iterables, ensuring that the input is always a sequence.
The input may or may not be a copy. To ensure copying, use #arrCopy.
Links: source; test/example.
Similar to #arr, but always makes a copy, even if the input is already a true array.
Links: source; test/example.
Like Array.prototype.slice but allows arbitrary s compatible with #arr.
Links: source; test/example.
Takes an arbitrary input and returns an array of its keys:
- For non-objects: always
[]. - For i with
.keys(): equivalent to converting the output of.keys()to an array. Implementation varies for performance.- Examples:
Array,Set,Map, and more.
- Examples:
- For l: equivalent to above for arrays.
- For i: exhausts the iterator, returning an array of indexes equivalent to
i.span(i.len(iterator)). See #spanand #len. - For r: equivalent to
Object.keys.
Links: source; test/example.
Takes an arbitrary input and returns an array of its values:
- For non-objects: always
[]. - For a: returns as-is without copying.
- For l: slice to array.
- For i with
.values(): equivalent to converting the output of.values()to an array. Implementation varies for performance.- Examples:
Set,Map, and more.
- Examples:
- For i: equivalent to
[...iterator]. - For r: equivalent to
Object.values.
Links: source; test/example.
Variant of #values that always makes a copy. Mutating the output doesn't affect the original.
Links: source; test/example.
Takes an arbitrary input and returns an array of its entries (key-value tuples):
- For non-objects: always
[]. - For i with
.entries(): equivalent to converting the output of.entries()to an array. Implementation varies for performance.- Examples:
Set,Map, and more.
- Examples:
- For l: equivalent to above for arrays.
- For i: exhausts the iterator, returning an array of entries where keys are indexes starting with 0.
- For r: equivalent to
Object.entries.
Links: source; test/example.
Takes an arbitrary value and attempts to deeply materialize it. Any i, or l that contain iterators, or lists that contain lists that contain iterators, etc., are converted to arrays. Does not inspect other data structures such as s or d.
Links: source; test/example.
Like Array.prototype.indexOf. Differences:
Links: source; test/example.
Signature: (List<A>, A => bool) => int.
Like Array.prototype.findIndex. Differences:
Links: source; test/example.
Like Array.prototype.includes. Differences:
Links: source; test/example.
Takes an arbitrary iterable compatible with #values and appends an arbitrary value, returning the resulting array.
Links: source; test/example.
Takes an arbitrary iterable compatible with #values and prepends an arbitrary value, returning the resulting array.
Links: source; test/example.
Like Array.prototype.concat. Differences:
- Takes two arguments, without rest/spread.
- Supports arbitrary iterables compatible with #
values. - Iterables may be n, equivalent to
[].
Note: for individual elements, use #append and
#prepend.
Links: source; test/example.
Universal length measurement:
- For non-objects: always 0.
- For iterables:
- For l: same as
.length. - For ES2015 collections such as
Set: same as.size. - For iterators: exhausts the iterator, returning element count.
- For l: same as
- For r: equivalent to
Object.keys(val).length.
Links: source; test/example.
Shortcut for #len > 0.
Links: source; test/example.
Signature: (Iter<A>, A => void) => void.
Similar to Array.prototype.forEach, Set.prototype.forEach, Map.prototype.forEach, and so on. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Doesn't support
thisor additional arguments.
Links: source; test/example.
Signature: (Iter<A>, A => B) => B[].
Similar to Array.prototype.map. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Doesn't support
this, and doesn't pass additional arguments. When you want support for additional arguments, use #valuesto convert an arbitrary iterable to an array, then use native.map.
Links: source; test/example.
Similar to Array.prototype.map. Differences:
- Mutates the input (which must be an array).
- Doesn't support
thisor additional arguments.
For a non-mutating version, see #map.
Links: source; test/example.
Signature: (Iter<A>, {new(A): B}) => B[].
Similar to #map, but instead of taking an arbitrary function, takes a class and calls it with new for each element.
import * as i from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/iter.mjs'
import * as o from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/obj.mjs'
class Model extends o.Dict {pk() {return this.id}}
class Person extends Model {}
console.log(i.mapCls(
[
{id: 1, name: `Mira`},
{id: 2, name: `Kara`},
],
Person,
))
/*
[
Person { id: 1, name: "Mira" },
Person { id: 2, name: "Kara" },
]
*/Links: source; test/example.
Equivalent to i.compact(i.map(val, fun)). See #map and #compact.
Links: source; test/example.
Signature: (Iter<A>, A => B[]) => B[].
Similar to Array.prototype.flatMap. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Doesn't support
thisor additional arguments.
This function is equivalent to i.flat(i.map(val, fun)). See #map and #flat.
Links: source; test/example.
Signature: (Iter<A>, A => bool) => A[].
Similar to Array.prototype.filter. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Doesn't support
thisor additional arguments.
Links: source; test/example.
Opposite of #filter. Equivalent to i.filter(val, l.not(fun)).
Links: source; test/example.
Equivalent to i.filter(val, l.id). Takes an arbitrary iterable and returns an array of its truthy #values, discarding falsy values.
Links: source; test/example.
Signature: (Iter<A>, A) => A[].
Takes an arbitrary iterable and an element to remove. Returns an array of the iterable's #values, discarding each occurrence of this element, comparing via is.
Links: source; test/example.
Signature: (src: Iter<A>, acc: B, fun: (B, A) => B) => B.
Similar to Array.prototype.reduce. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Arguments are
(src, acc, fun)rather than(fun, acc). - Accumulator argument is mandatory.
- Doesn't support
this. - Iterator function receives exactly two arguments: accumulator and next value.
Links: source; test/example.
Signature: (src: Iter<A>, fun: (A, A) => A) => A.
Similar to #fold but instead of taking an accumulator argument, uses the first element of the iterable as the initial accumulator value. If the iterable is empty, returns undefined.
Similar to Array.prototype.reduce when invoked without an accumulator argument.
Links: source; test/example.
Signature: (Iter<A>, A => bool) => A.
Similar to Array.prototype.find. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Doesn't support
thisor additional arguments.
Links: source; test/example.
Signature: (src: Iter<A>, fun: A => B) => B.
Similar to #find, but returns the first truthy result of calling the iterator function, rather than the corresponding element. Equivalent to i.find(i.map(src, fun), l.id) but more efficient.
Links: source; test/example.
Signature: (Iter<A>, A => bool) => bool.
Similar to Array.prototype.every. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Doesn't support
thisor additional arguments.
Links: source; test/example.
Signature: (Iter<A>, A => bool) => bool.
Similar to Array.prototype.some. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Doesn't support
thisor additional arguments.
Links: source; test/example.
Similar to Array.prototype.flat. Differences:
- Takes an arbitrary iterable compatible with #
values. - Always flattens to infinite depth.
Currently flattens only children and descendants that are p, preserving other nested iterables as-is.
Links: source; test/example.
Takes an arbitrary iterable compatible with #values and returns its first element or undefined.
Links: source; test/example.
Takes an arbitrary iterable compatible with #values and returns its last element or undefined.
Links: source; test/example.
Short for "initial". Takes an arbitrary iterable compatible with #values and returns an array of all its values except last.
Links: source; test/example.
Takes an arbitrary iterable compatible with #values and returns an array of all its values except first.
Links: source; test/example.
Takes an arbitrary iterable compatible with #values and returns N values from the start.
Links: source; test/example.
Signature: (src: Iter<A>, fun: A => B) => nat.
Takes an arbitrary iterable compatible with #values, calls the given function for each value, and returns the count of truthy results. The count is between 0 and iterable length.
Links: source; test/example.
Signature: (a, b) => -1 | 0 | 1.
Equivalent to the default JS sort comparison algorithm. Sometimes useful for sorting via Array.prototype.sort or #sort, as a fallback.
Links: source; test/example.
Signature: (a, b) => -1 | 0 | 1 where arguments are n or f.
Sort comparison for finite numbers. Usable for Array.prototype.sort or #sort. Throws on non-nil, non-finite arguments.
Links: source; test/example.
Signature: (src: Iter<A>, fun?: (prev: A, next: A) => -1 | 0 | 1) => A[].
Similar to Array.prototype.sort. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Always creates a new array. Does not mutate the input.
The comparison function is optional. If omitted, default JS sorting is used.
Links: source; test/example.
Similar to Array.prototype.reverse. Differences:
- Takes an arbitrary iterable compatible with #
values. - Iterable may be n, equivalent to
[]. - Always creates a new array. Does not mutate the input.
Links: source; test/example.
Signature: (Iter<A>, A => Key | any) => {[Key: A]}.
Takes an arbitrary iterable compatible with #values and returns an index where its values are indexed by the given function, hence the name. The function is called for each value. If the function returns a v, the key-value pair is added to the index. Invalid keys are ignored. If the function returns the same key for multiple values, previous values are lost.
Compare #group which keeps all values for each group, rather than only the last.
Links: source; test/example.
Signature: (Iter<A>, A => Key | any) => {[Key: A[]]}.
Takes an arbitrary iterable compatible with #values and groups its values by keys generated by the given function. The function is called for each value. If the function returns a v, the value is added to the index under that key. Invalid keys are ignored.
Compare #index, which keeps only the last value for each group.
Links: source; test/example.
Signature: (Iter<A>, A => bool) => [A[], A[]].
Partitions the #values of a given iterable, returning a tuple of two groups: values that satisfy the predicate and the remainder.
Links: source; test/example.
Signature: (Iter<A>) => fin.
Sums all finite #values of an arbitrary iterable, ignoring all non-finite values.
Links: source; test/example.
Signature: (Iter<[Key, A]>) => {[Key: A]}.
Similar to Object.fromEntries. Differences:
- Takes an arbitrary iterable compatible with #
values(more flexible).- Each value of this iterable must be a key-value pair.
- Ignores entries where the first element is not a v.
- Returns a n.
- Slightly slower.
Links: source; test/example.
Signature: (min: int, max: int) => int[].
Returns an array of contiguous integers in the range of [min, max). The first value is min, the last value is max - 1.
Links: source; test/example.
Signature: nat => nat[].
Returns an array of the given length, where values are integers from 0. Shortcut for i.range(0, length). Nil length is equivalent to 0.
Links: source; test/example.
Signature: (len: nat, fun: nat => A) => A[].
Takes an array length and a mapping function. Returns an array of the given length, where each element is the result of calling the given function, passing the element's index, starting with 0. Equivalent to i.mapMut(i.span(len), fun).
Links: source; test/example.
Signature: (len: nat, val: A) => A[].
Returns an array of the given length where each element is the given value. Equivalent to i.alloc(len).fill(val).
Links: source; test/example.
Signature: ({[Key: A]}, A => B) => {[Key: B]}.
Similar to #map but for dicts.
- The input must be either n or a r. Nil is considered
{}. - The output is always a p with the same keys but altered values.
- The mapping function receives only one argument: each value.
import * as i from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/iter.mjs'
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
i.mapDict({one: 10, two: 20}, l.inc)
// {one: 11, two: 21}Performance note: dictionary iteration is much slower than array iteration, and should be avoided or minimized.
Links: source; test/example.
Signature: ({[Key: A]}, A => bool) => {[Key: A]}.
Similar to #filter but for dicts.
- The input must be either n or a r. Nil is considered
{}. - The output is always a p. It has only the key-values from the original input for which the given function returned a truthy result.
- The mapping function receives each value.
import * as i from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/iter.mjs'
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
i.pick({one: -20, two: -10, three: 10, four: 20}, l.isFinPos)
// {three: 10, four: 20}Performance note: dictionary iteration is much slower than array iteration, and should be avoided or minimized.
Links: source; test/example.
Signature: ({[Key: A]}, A => bool) => {[Key: A]}.
Similar to #reject but for dicts.
- The input must be either n or a r. Nil is considered
{}. - The output is always a p. It has only the key-values from the original input for which the given function returned a falsy result.
- The mapping function receives each value.
import * as i from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/iter.mjs'
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
i.omit({one: -20, two: -10, three: 10, four: 20}, l.isFinPos)
// {one: -20, two: -10}Performance note: dictionary iteration is much slower than array iteration, and should be avoided or minimized.
Links: source; test/example.
Signature: ({[Key: A]}, Iter<Key>) => {[Key: A]}.
Similar to [#pick](#function-pick) but uses keys instead of a function.
- The input must be either n or a r. Nil is considered
{}. - The output is always a p. It mirrors the original, but has only "known" given keys, excluding any other.
Performance note: dictionary iteration is much slower than array iteration, and should be avoided or minimized.
Links: source; test/example.
Signature: ({[Key: A]}, Iter<Key>) => {[Key: A]}.
Similar to [#omit](#function-omit) but uses keys instead of a function.
- The input must be either n or a r. Nil is considered
{}. - The output is always a p. It mirrors the original, but has only "unknown" keys, excluding any given keys.
Performance note: dictionary iteration is much slower than array iteration, and should be avoided or minimized.
The following APIs are exported but undocumented. Check iter.mjs.