node package manager
Painless code sharing. npm Orgs help your team discover, share, and reuse code. Create a free org »

itertools

npm Build Status Coverage Status

A JavaScript port of Python's awesome itertools standard library.

Usage example:

>>> import { izip, cycle } from 'itertools';
>>>
>>> const xs = [1, 2, 3, 4];
>>> const ys = ['hello', 'there'];
>>> for (const [x, y] of izip(xs, cycle(ys))) {
>>>     console.log(x, y);
>>> }
1 'hello'
2 'there'
3 'hello'
4 'there'

About argument order

In Python, many of the itertools take a function as an argument. In the JS port of these we initially kept these orderings the same to stick closely to the Python functions, but in practice, it turns out to be more pragmatic to flip them, so the function gets to be the second param. Example:

In Python:

map(fnitems)

But in JavaScript:

map(itemsfn)

The rationale for this flipping of argument order is because in practice, the function bodies can span multiple lines, in which case the following block will remaing aesthetically pleasing:

import { map } from 'itertools';
 
const numbers = [1, 2, 3];
const squares = map(numbers, n => {
 
    //
    // Do something wild with these numbers here
    //
    // ...
    return n * n;
 
});

API

The itertools package consists of a few building blocks:

Ports of builtins

# all(iterable: Iterable<T>, keyFn?: Predicate<T>): boolean <>

Returns true when all of the items in iterable are truthy. An optional key function can be used to define what truthiness means for this specific collection.

Examples:

all([])                           // => true
all([0])                          // => false
all([0, 1, 2])                    // => false
all([1, 2, 3])                    // => true

Examples with using a key function:

all([2, 4, 6], n => n % 2 === 0)  // => true
all([2, 4, 5], n => n % 2 === 0)  // => false

# any(iterable: Iterable<T>, keyFn?: Predicate<T>): boolean <>

Returns true when any of the items in iterable are truthy. An optional key function can be used to define what truthiness means for this specific collection.

Examples:

any([])                           // => false
any([0])                          // => false
any([0, 1, null, undefined])      // => true

Examples with using a key function:

any([1, 4, 5], n => n % 2 === 0)  // => true
any([{name: 'Bob'}, {name: 'Alice'}], person => person.name.startsWith('C'))  // => false

# contains(haystack: Iterable<T>, needle: T): boolean <>

Returns true when any of the items in the iterable are equal to the target object.

Examples:

contains([], 'whatever')         // => false
contains([3], 42)                // => false
contains([3], 3)                 // => true
contains([0, 1, 2], 2)           // => true

# enumerate(iterable: Iterable<T>, start: number = 0): Iterable<[number, T]> <>

Returns an iterable of enumeration pairs. Iterable must be a sequence, an iterator, or some other object which supports iteration. The elements produced by returns a tuple containing a counter value (starting from 0 by default) and the values obtained from iterating over given iterable.

Example:

import { enumerate } from 'itertools';
 
console.log([...enumerate(['hello', 'world'])]);
// [0, 'hello'], [1, 'world']]

# filter(iterable: Iterable<T>, predicate: Predicate<T>): Array<T> <>

Non-lazy version of ifilter.

# iter(iterable: Iterable<T>): Iterator<T> <>

Returns an iterator object for the given iterable. This can be used to manually get an iterator for any iterable datastructure. The purpose and main use case of this function is to get a single iterator (a thing with state, think of it as a "cursor") which can only be consumed once.

# map(iterable: Iterable<T>, mapper: T => V): Array<V> <>

Non-lazy version of imap.

# max(iterable: Iterable<T>, keyFn?: T => number): Maybe<T> <>

Return the largest item in an iterable. Only works for numbers, as ordering is pretty poorly defined on any other data type in JS. The optional keyFn argument specifies a one-argument ordering function like that used for sorted.

If the iterable is empty, undefined is returned.

If multiple items are maximal, the function returns either one of them, but which one is not defined.

# min(iterable: Iterable<T>, keyFn?: T => number): Maybe<T> <>

Return the smallest item in an iterable. Only works for numbers, as ordering is pretty poorly defined on any other data type in JS. The optional keyFn argument specifies a one-argument ordering function like that used for sorted.

If the iterable is empty, undefined is returned.

If multiple items are minimal, the function returns either one of them, but which one is not defined.

# range(start: number): Iterable<number> <>
# range(start: number, stop: number, step: number = 1): Iterable<number> <>

Returns an iterator producing all the numbers in the given range one by one, starting from start (default 0), as long as i < stop, in increments of step (default 1).

range(a) is a convenient shorthand for range(0, a).

Various valid invocations:

range(5)           // [0, 1, 2, 3, 4]
range(0, 5)        // [0, 1, 2, 3, 4]
range(0, 5, 2)     // [0, 2, 4]
range(5, 0, -1)    // [5, 4, 3, 2, 1]
range(-3)          // []

For a positive step, the iterator will keep producing values n as long as the stop condition n < stop is satisfied.

For a negative step, the iterator will keep producing values n as long as the stop condition n > stop is satisfied.

The produced range will be empty if the first value to produce already does not meet the value constraint.

# reduce(iterable: Iterable<T>, reducer: (O, T, number) => O, start: O): O <>
# reduce_(iterable: Iterable<T>, reducer: (T, T, number) => T): Maybe<T> <>

Apply function of two arguments cumulatively to the items of sequence, from left to right, so as to reduce the sequence to a single value. For example:

reduce([1, 2, 3, 4, 5], (x, y) => x + y, 0)

calculates

(((((0+1)+2)+3)+4)+5)

The left argument, x, is the accumulated value and the right argument, y, is the update value from the sequence.

Difference between reduce() and reduce\_(): reduce() requires an explicit initializer, whereas reduce_() will automatically use the first item in the given iterable as the initializer. When using reduce(), the initializer value is placed before the items of the sequence in the calculation, and serves as a default when the sequence is empty. When using reduce_(), and the given iterable is empty, then no default value can be derived and undefined will be returned.

# sorted(iterable: Iterable<T>, keyFn?: T => Primitive, reverse?: boolean): Array<T> <>

Return a new sorted list from the items in iterable.

Has two optional arguments:

  • keyFn specifies a function of one argument providing a primitive identity for each element in the iterable. that will be used to compare. The default value is to use a default identity function that is only defined for primitive types.

  • reverse is a boolean value. If true, then the list elements are sorted as if each comparison were reversed.

# sum(iterable: Iterable<number>): number <>

Sums the items of an iterable from left to right and returns the total. The sum will defaults to 0 if the iterable is empty.

# zip(xs: Iterable<T1>, ys: Iterable<T2>): Array<[T1, T2]> <>
# zip3(xs: Iterable<T1>, ys: Iterable<T2>, zs: Iterable<T3>): Array<[T1, T2, T3]> <>

Non-lazy version of izip / izip3.

Ports of itertools

# chain(...iterables: Array<Iterable<T>>): Iterable<T> <>

Returns an iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted. Used for treating consecutive sequences as a single sequence.

# compress(iterable: Iterable<T>, selectors: Iterable<boolean>): Array<T> <>

Non-lazy version of icompress.

# count(start: number, step: number): Iterable<number> <>

Returns an iterator that counts up values starting with number start (default 0), incrementing by step. To decrement, use a negative step number.

# cycle(iterable: Iterable<T>): Iterable<T> <>

Returns an iterator producing elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely.

# dropwhile(iterable: Iterable<T>, predicate: T => bool): Iterable<T> <>

Returns an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every remaining element. Note: the iterator does not produce any output until the predicate first becomes false.

# icompress(iterable: Iterable<T>, selectors: Iterable<boolean>): Iterable<T> <>

Returns an iterator that filters elements from data returning only those that have a corresponding element in selectors that evaluates to true. Stops when either the data or selectors iterables has been exhausted.

# ifilter(iterable: Iterable<T>, predicate: Predicate<T>): Iterable<T> <>

Returns an iterator that filters elements from iterable returning only those for which the predicate is true.

# imap(iterable: Iterable<T>, mapper: T => V): Iterable<V> <>

Returns an iterator that computes the given mapper function using arguments from each of the iterables.

# islice(iterable: Iterable<T>[, start: number], stop: number[, step: number]): Iterable<T> <>

Returns an iterator that returns selected elements from the iterable. If start is non-zero, then elements from the iterable are skipped until start is reached. Then, elements are returned by making steps of step (defaults to 1). If set to higher than 1, items will be skipped. If stop is provided, then iteration continues until the iterator reached that index, otherwise, the iterable will be fully exhausted. islice() does not support negative values for start, stop, or step.

# izip(xs: Iterable<T1>, ys: Iterable<T2>): Iterable<[T1, T2]> <>
# izip3(xs: Iterable<T1>, ys: Iterable<T2>, zs: Iterable<T3>): Iterable<[T1, T2, T3]> <>

Returns an iterator that aggregates elements from each of the iterables. Used for lock-step iteration over several iterables at a time. When iterating over two iterables, use izip2. When iterating over three iterables, use izip3, etc. izip is an alias for izip2.

# izipLongest(xs: Iterable<T1>, ys: Iterable<T2>, filler?: D): Iterable<[T1 | D, T2 | D]> <>
# izipLongest3(xs: Iterable<T1>, ys: Iterable<T2>, zs: Iterable<T3>, filler?: D): Iterable<[T1 | D, T2 | D, T3 | D]> <>

Returns an iterator that aggregates elements from each of the iterables. If the iterables are of uneven length, missing values are filled-in with fillvalue. Iteration continues until the longest iterable is exhausted.

# izipMany(...iters: Array<Iterable<T>>): Iterable<Array<T>> <>

Like the other izips (izip, izip3, etc), but generalized to take an unlimited amount of input iterables. Think izip(*iterables) in Python.

Note: Due to Flow type system limitations, you can only "generially" zip iterables with homogeneous types, so you cannot mix types like <A, B> like you can with izip().

# permutations(iterable: Iterable<T>, r: number = undefined): Iterable<Array> <>

Return successive r-length permutations of elements in the iterable.

If r is not specified, then r defaults to the length of the iterable and all possible full-length permutations are generated.

Permutations are emitted in lexicographic sort order. So, if the input iterable is sorted, the permutation tuples will be produced in sorted order.

Elements are treated as unique based on their position, not on their value. So if the input elements are unique, there will be no repeat values in each permutation.

# repeat(thing: T, times: number = undefined): Iterable<T> <>

Returns an iterator that produces values over and over again. Runs indefinitely unless the times argument is specified.

# takewhile(iterable: Iterable<T>, predicate: T => bool): Iterable<T> <>

Returns an iterator that produces elements from the iterable as long as the predicate is true.

# zipLongest(xs: Iterable<T1>, ys: Iterable<T2>, filler?: D): Array<[T1 | D, T2 | D]> <>
# zipLongest3(xs: Iterable<T1>, ys: Iterable<T2>, zs: Iterable<T3>, filler?: D): Array<[T1 | D, T2 | D, T3 | D]> <>

Non-lazy version of izipLongest and friends.

# zipMany(...iters: Array<Iterable<T>>): Array<Array<T>> <>

Non-lazy version of izipMany.

Ports of more-itertools

# chunked(iterable: Iterable<T>, size: number): Iterable<Array<T>> <>

Break iterable into lists of length size:

>>> [...chunked([1, 2, 3, 4, 5, 6], 3)]
[[1, 2, 3], [4, 5, 6]]

If the length of iterable is not evenly divisible by size, the last returned list will be shorter:

>>> [...chunked([1, 2, 3, 4, 5, 6, 7, 8], 3)]
[[1, 2, 3], [4, 5, 6], [7, 8]]

# flatten(iterableOfIterables: Iterable<Iterable<T>>): Iterable<T> <>

Return an iterator flattening one level of nesting in a list of lists:

>>> [...flatten([[0, 1], [2, 3]])]
[0, 1, 2, 3]

# intersperse(value: T, iterable: Iterable<T>): Iterable<T> <>

Intersperse filler element value among the items in iterable.

>>> [...intersperse(-1, range(1, 5))]
[1, -1, 2, -1, 3, -1, 4]

# itake(n: number, iterable: Iterable<T>): Iterable<T> <>

Returns an iterable containing only the first n elements of the given iterable.

# pairwise(iterable: Iterable<T>): Iterable<[T, T]> <>

Returns an iterator of paired items, overlapping, from the original. When the input iterable has a finite number of items n, the outputted iterable will have n - 1 items.

>>> pairwise([8, 2, 0, 7])
[(8, 2), (2, 0), (0, 7)]

# partition(iterable: Iterable<T>, predicate: Predicate<T>): [Array<T>, Array<T>] <>

Returns a 2-tuple of arrays. Splits the elements in the input iterable into either of the two arrays. Will fully exhaust the input iterable. The first array contains all items that match the predicate, the second the rest:

>>> const isOdd = x => x % 2 !== 0;
>>> const iterable = range(10);
>>> const [odds, evens] = partition(iterable, isOdd);
>>> odds
[1, 3, 5, 7, 9]
>>> evens
[0, 2, 4, 6, 8]

# roundrobin(...iterables: Array<Iterable<T>>): Iterable<T> <>

Yields the next item from each iterable in turn, alternating between them. Continues until all items are exhausted.

>>> [...roundrobin([1, 2, 3], [4], [5, 6, 7, 8])]
[1, 4, 5, 2, 6, 3, 7, 8]

# take(n: number, iterable: Iterable<T>): Array<T> <>

Non-lazy version of itake.

# uniqueEverseen(iterable: Iterable<T>, keyFn?: T => Primitive): Iterable<T> <>

Yield unique elements, preserving order.

>>> [...uniqueEverseen('AAAABBBCCDAABBB')]
['A', 'B', 'C', 'D']
>>> [...uniqueEverseen('AbBCcAB', s => s.toLowerCase())]
['A', 'b', 'C']

# uniqueJustseen(iterable: Iterable<T>, keyFn?: T => Primitive): Iterable<T> <>

Yields elements in order, ignoring serial duplicates.

>>> [...uniqueJustseen('AAAABBBCCDAABBB')]
['A', 'B', 'C', 'D', 'A', 'B']
>>> [...uniqueJustseen('AbBCcAB', s => s.toLowerCase())]
['A', 'b', 'C', 'A', 'B']

Additions

# compact(iterable: Iterable<T>): Array<$NonMaybeType<T>> <>

Non-lazy version of icompact.

# compactObject<O: { [key: string]: any }>(obj: O): $ObjMap<O, <T>(Maybe<T>) => T> <>

NOTE: 🙀 OMG, that type signature! Don't panic. Just look at the example :)

Removes all undefined values from the given object. Returns a new object.

>>> compactObject({ a: 1, b: undefined, c: 0 })
{ a: 1, c: 0 }

# first(iterable: Iterable<T>, keyFn?: Predicate<T>): Maybe<T> <>

Returns the first item in the iterable for which the predicate holds, if any. If no such item exists, undefined is returned. The default predicate is any defined value.

# flatmap(iterable: Iterable<T>, mapper: T => Iterable<S>): Iterable<S> <>

Returns 0 or more values for every value in the given iterable. Technically, it's just calling map(), followed by flatten(), but it's a very useful operation if you want to map over a structure, but not have a 1:1 input-output mapping. Instead, if you want to potentially return 0 or more values per input element, use flatmap():

For example, to return all numbers n in the input iterable n times:

>>> const repeatN = n => repeat(n, n);
>>> [...flatmap([0, 1, 2, 3, 4], repeatN)]
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]  // note: no 0

# icompact(iterable: Iterable<T>): Iterable<$NonMaybeType<T>> <>

Returns an iterable, filtering out any undefined values from the input iterable. This function is useful to convert a list of Maybe<T>'s to a list of T's, discarding all the undefined values:

>>> compact([1, 2, undefined, 3])
[1, 2, 3]