Skip to content

Smoren/itertools-ts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IterTools for TypeScript and JavaScript

npm npm Coverage Status Build and test Minified Size License: MIT

IterTools Logo

Inspired by Python — designed for TypeScript.

Features

IterTools makes you an iteration superstar by providing two types of tools:

  • Loop iteration tools
  • Stream iteration tools

Loop Iteration Tools Example

import { multi } from 'itertools-ts';

for (const [letter, number] of multi.zip(['a', 'b'], [1, 2])) {
  console.log(`${letter}${number}`);  // a1, b2
}

// Async example
const letters = ['a', 'b'].map((x) => Promise.resolve(x));
const numbers = [1, 2].map((x) => Promise.resolve(x));

for await (const [letter, number] of multi.zipAsync(letters, numbers)) {
  console.log(`${letter}${number}`);  // a1, b2
}

Stream Iteration Tools Example

import { Stream, AsyncStream } from 'itertools-ts';

const result1 = Stream.of([1, 1, 2, 2, 3, 4, 5])
  .distinct()             // [1, 2, 3, 4, 5]
  .map((x) => x**2)       // [1, 4, 9, 16, 25]
  .filter((x) => x < 10)  // [1, 4, 9]
  .toSum();               // 14

// Async example
const result2 = await AsyncStream.of([1, 1, 2, 2, 3, 4, 5].map((x) => Promise.resolve(x)))
  .distinct()             // [1, 2, 3, 4, 5]
  .map((x) => x**2)       // [1, 4, 9, 16, 25]
  .filter((x) => x < 10)  // [1, 4, 9]
  .toSum();               // 14

More about Streams

All functions work on iterable collections and iterators:

  • Array
  • Set
  • Map
  • String
  • Generator
  • Iterable
  • Iterator

Every function have an analog with "Async"-suffixed name for working with async iterable and iterators (e.g. zip and zipAsync):

  • AsyncIterable
  • AsyncIterator

If an asynchronous function takes other functions as input, they can also be asynchronous.

import { single } from 'itertools-ts';

const starWarsEpisodes = [1, 2, 3, 4, 5, 6, 7, 8, 9];

for await (const goodMovie of single.filterAsync(
  starWarsEpisodes,
  async (episode) => {
    return Promise.resolve(episode > 3 && episode < 8);
  }
)) {
  console.log(goodMovie);
}
// 4, 5, 6, 7

Setup

npm i itertools-ts

Similar Libraries in Other Languages

IterTools functionality is not limited to TypeScript and Python. Other languages have similar libraries. Familiar functionality is available when working in other languages.

Quick Reference

Loop Iteration Tools

Multi Iteration

Iterator Description Sync Code Snippet Async Code Snippet
chain Chain multiple iterables together multi.chain(list1, list2, ...) multi.chainAsync(list1, list2, ...)
zip Iterate multiple collections simultaneously until the shortest iterator completes multi.zip(list1, list2, ...) multi.zipAsync(list1, list2, ...)
zipEqual Iterate multiple collections of equal length simultaneously, error if lengths not equal multi.zipEqual(list1, list2, ...) multi.zipEqualAsync(list1, list2, ...)
zipFilled Iterate multiple collections simultaneously until the longest iterator completes (with filler for uneven lengths) multi.zipFilled(filler, list1, list2, ...) multi.zipFilledAsync(filler, list1, list2, ...)
zipLongest Iterate multiple collections simultaneously until the longest iterator completes multi.zipLongest(list1, list2, ...) multi.zipLongestAsync(list1, list2, ...)

Single Iteration

Iterator Description Sync Code Snippet Async Code Snippet
chunkwise Iterate by chunks single.chunkwise(data, chunkSize) single.chunkwiseAsync(data, chunkSize)
chunkwiseOverlap Iterate by overlapped chunks single.chunkwiseOverlap(data, chunkSize, overlapSize) single.chunkwiseOverlapAsync(data, chunkSize, overlapSize)
compress Filter out elements not selected single.compress(data, selectors) single.compressAsync(data, selectors)
dropWhile Drop elements while predicate is true single.dropWhile(data, predicate) single.dropWhileAsync(data, predicate)
enumerate Enumerates elements of collection single.enumerate(data) single.enumerateAsync(data)
filter Filter for elements where predicate is true single.filter(data, predicate) single.filterAsync(data, predicate)
flatMap Map function onto items and flatten result single.flatMap(data, mapper) single.flatMapAsync(data, mapper)
flatten Flatten multidimensional iterable single.flatten(data, [dimensions]) single.flattenAsync(data, [dimensions])
groupBy Group data by a common element single.groupBy(data, groupKeyFunction, [itemKeyFunc]) single.groupByAsync(data, groupKeyFunction, [itemKeyFunc])
limit Iterate up to a limit single.limit(data, limit) single.limitAsync(data, limit)
keys Iterate keys of key-value pairs single.keys(data) single.keysAsync(data)
map Map function onto each item single.map(data, mapper) single.mapAsync(data, mapper)
pairwise Iterate successive overlapping pairs single.pairwise(data) single.pairwiseAsync(data)
repeat Repeat an item a number of times single.repeat(item, repetitions) single.repeatAsync(item, repetitions)
skip Iterate after skipping elements single.skip(data, count, [offset]) single.skipAsync(data, count, [offset])
slice Extract a slice of the iterable single.slice(data, [start], [count], [step]) single.sliceAsync(data, [start], [count], [step])
sort Iterate a sorted collection single.sort(data, [comparator]) single.sortAsync(data, [comparator])
takeWhile Iterate elements while predicate is true single.takeWhile(data, predicate) single.takeWhileAsync(data, predicate)
values Iterate values of key-value pairs single.values(data) single.valuesAsync(data)

Infinite Iteration

Iterator Description Code Snippet
count Count sequentially forever infinite.count([start], [step])
cycle Cycle through a collection infinite.cycle(iterable)
repeat Repeat an item forever infinite.repeat(item)

Math Iteration

Iterator Description Sync Code Snippet Async Code Snippet
runningAverage Running average accumulation math.runningAverage(numbers, [initialValue]) math.runningAverageAsync(numbers, [initialValue])
runningDifference Running difference accumulation math.runningDifference(numbers, [initialValue]) math.runningDifferenceAsync(numbers, [initialValue])
runningMax Running maximum accumulation math.runningMax(numbers, [initialValue]) math.runningMax(numbers, [initialValue])
runningMin Running minimum accumulation math.runningMin(numbers, [initialValue]) math.runningMinAsync(numbers, [initialValue])
runningProduct Running product accumulation math.runningProduct(numbers, [initialValue]) math.runningProductAsync(numbers, [initialValue])
runningTotal Running total accumulation math.runningTotal(numbers, [initialValue]) math.runningTotalAsync(numbers, [initialValue])

Reduce

Reducer Description Sync Code Snippet Async Code Snippet
toAverage Mean average of elements reduce.toAverage(numbers) reduce.toAverageAsync(numbers)
toCount Reduce to length of iterable reduce.toCount(data) reduce.toCountAsync(data)
toFirst Reduce to its first value reduce.toFirst(data) reduce.toFirstAsync(data)
toFirstAndLast Reduce to its first and last values reduce.toFirstAndLast(data) reduce.toFirstAndLastAsync(data)
toLast Reduce to its last value reduce.toLast(data) reduce.toLastAsync(data)
toMax Reduce to its greatest element reduce.toMax(numbers, [compareBy]) reduce.toMaxAsync(numbers, [compareBy])
toMin Reduce to its smallest element reduce.toMin(numbers, [compareBy]) reduce.toMinAsync(numbers, [compareBy])
toMinMax Reduce to its lower and upper bounds reduce.toMinMax(numbers, [compareBy]) reduce.toMinMaxAsync(numbers, [compareBy])
toProduct Reduce to the product of its elements reduce.toProduct(numbers) reduce.toProductAsync(numbers)
toRange Reduce to difference of max and min values reduce.toRange(numbers) reduce.toRangeAsync(numbers)
toSum Reduce to the sum of its elements reduce.toSum(numbers) reduce.toSumAsync(numbers)
toValue Reduce to value using callable reducer reduce.toValue(data, reducer, initialValue) reduce.toValueAsync(data, reducer, initialValue)

Set and multiset Iteration

Iterator Description Sync Code Snippet Async Code Snippet
cartesianProduct Iterate cartesian product of iterables set.cartesianProduct(...iterables) set.cartesianProductAsync(...iterables)
distinct Iterate only distinct items set.distinct(data) set.distinctAsync(data)
intersection Intersection of iterables set.intersection(...iterables) set.intersectionAsync(...iterables)
partialIntersection Partial intersection of iterables set.partialIntersection(minCount, ...iterables) set.partialIntersectionAsync(minCount, ...iterables)
symmetricDifference Symmetric difference of iterables set.symmetricDifference(...iterables) set.symmetricDifferenceAsync(...iterables)
union Union of iterables set.union(...iterables) set.unionAsync(...iterables)

Summary

Summary Description Sync Code Snippet Async Code Snippet
allMatch True if all items are true according to predicate summary.allMatch(data, predicate) summary.allMatchAsync(data, predicate)
allUnique True if all elements in collection are unique summary.allUnique(data) summary.allUniqueAsync(data)
anyMatch True if any item is true according to predicate summary.anyMatch(data, predicate) summary.anyMatchAsync(data, predicate)
exactlyN True if exactly n items are true according to predicate summary.exactlyN(data, n, predicate) summary.exactlyNAsync(data, n, predicate)
isAsyncIterable True if given data is async iterable summary.isAsyncIterable(data) —
isIterable True if given data is iterable summary.isIterable(data) —
isIterator True if given data is iterator summary.isIterator(data) —
isReversed True if iterable reverse sorted summary.isReversed(data) summary.isReversedAsync(data)
isSorted True if iterable sorted summary.isSorted(data) summary.isSortedAsync(data)
isString True if given data is string summary.isString(data) summary.isStringAsync(data)
noneMatch True if none of items true according to predicate summary.noneMatch(data, predicate) summary.noneMatchAsync(data, predicate)
same True if collections are the same summary.same(...collections) summary.sameAsync(...collections)
sameCount True if collections have the same lengths summary.sameCount(...collections) summary.sameCountAsync(...collections)

Transform

Iterator Description Sync Code Snippet Async Code Snippet
tee Iterate duplicate iterables transform.tee(data, count) transform.teeAsync(data, count)
toArray Transforms collection to array transform.toArray(data) transform.toArrayAsync(data)
toAsyncIterable Transforms collection to async iterable transform.toAsyncIterable(data) —
toAsyncIterator Transforms collection to async iterator transform.toAsyncIterator(data) —
toIterable Transforms collection to iterable transform.toIterable(data) —
toIterator Transforms collection to iterator transform.toIterator(data) —
toMap Transforms collection to map transform.toMap(pairs) transform.toMapAsync(pairs)
toSet Transforms collection to set transform.toSet(data) transform.toSetAsync(data)

Stream and AsyncStream Iteration Tools

Stream Sources

Source Description Sync Code Snippet Async Code Snippet
of Create a stream from an iterable Stream.of(iterable) AsyncStream.of(iterable)
ofEmpty Create an empty stream Stream.ofEmpty() AsyncStream.ofEmpty()
ofCount Create an infinite count stream Stream.ofCount([start], [step]) AsyncStream.ofCount([start], [step])
ofCycle Create an infinite cycle stream Stream.ofCycle(iterable) AsyncStream.ofCycle(iterable)
ofRepeat Create an infinite repeating stream Stream.ofRepeat(item) AsyncStream.ofRepeat(item)

Stream Operations

Operation Description Code Snippet
cartesianProductWith Iterate cartesian product of iterable source with another iterable collections stream.cartesianProductWith(...iterables)
chainWith Chain iterable source withs given iterables together into a single iteration stream.chainWith(...iterables)
chunkwise Iterate by chunks stream.chunkwise(chunkSize)
chunkwiseOverlap Iterate by overlapped chunks stream.chunkwiseOverlap(chunkSize, overlap)
compress Compress source by filtering out data not selected stream.compress(selectors)
distinct Filter out elements: iterate only unique items stream.distinct()
dropWhile Drop elements from the iterable source while the predicate function is true stream.dropWhile(predicate)
enumerate Enumerates elements of stream stream.enumerate()
filter Filter for only elements where the predicate function is true stream.filter(predicate)
flatMap Map function onto elements and flatten result stream.flatMap(mapper)
flatten Flatten multidimensional stream stream.flatten([dimensions])
intersectionWith Intersect stream and given iterables stream.intersectionWith(...iterables)
groupBy Group stram data by a common data element stream.groupBy(groupKeyFunction, [itemKeyFunc])
keys Iterate keys of key-value pairs from stream stream.keys()
limit Limit the stream's iteration stream.limit(limit)
map Map function onto elements stream.map(mapper)
pairwise Return pairs of elements from iterable source stream.pairwise()
partialIntersectionWith Partially intersect stream and given iterables stream.partialIntersectionWith(minIntersectionCount, ...iterables)
runningAverage Accumulate the running average (mean) over iterable source stream.runningAverage([initialValue])
runningDifference Accumulate the running difference over iterable source stream.runningDifference([initialValue])
runningMax Accumulate the running max over iterable source stream.runningMax([initialValue])
runningMin Accumulate the running min over iterable source stream.runningMin([initialValue])
runningProduct Accumulate the running product over iterable source stream.runningProduct([initialValue])
runningTotal Accumulate the running total over iterable source stream.runningTotal([initialValue])
skip Skip some elements of the stream stream.skip(count, [offset])
slice Extract a slice of the stream stream.slice([start], [count], [step])
sort Sorts the stream stream.sort([comparator])
symmetricDifferenceWith Symmetric difference of stream and given iterables stream.symmetricDifferenceWith(...iterables)
takeWhile Return elements from the iterable source as long as the predicate is true stream.takeWhile(predicate)
unionWith Union of stream and given iterables stream.union(...iterables)
values Iterate values of key-value pairs from stream stream.values()
zipWith Iterate iterable source with another iterable collections simultaneously stream.zipWith(...iterables)
zipEqualWith Iterate iterable source with another iterable collections of equal lengths simultaneously stream.zipEqualWith(...iterables)
zipFilledWith Iterate iterable source with another iterable collections simultaneously (with filler) stream.zipFilledWith(filler, ...iterables)
zipLongestWith Iterate iterable source with another iterable collections simultaneously stream.zipLongestWith(...iterables)

Stream Terminal Operations

Transformation Terminal Operations
Terminal Operation Description Code Snippet
tee Returns array of multiple identical Streams stream.tee(count)
toArray Returns array of stream elements stream.toArray()
toMap Returns map of stream elements (key-value pairs) stream.toMap()
toSet Returns set of stream elements stream.toSet()
Reduction Terminal Operations
Terminal Operation Description Code Snippet
toAverage Reduces stream to the mean average of its items stream.toAverage()
toCount Reduces stream to its length stream.toCount()
toFirst Reduces stream to its first value stream.toFirst()
toFirstAndLast Reduces stream to its first and last values stream.toFirstAndLast()
toLast Reduces stream to its last value stream.toLast()
toMax Reduces stream to its max value stream.toMax([compareBy])
toMin Reduces stream to its min value stream.toMin([compareBy])
toMin Reduce stream to its lower and upper bounds stream.toMinMax([compareBy])
toProduct Reduces stream to the product of its items stream.toProduct()
toRange Reduces stream to difference of max and min values stream.toRange()
toSum Reduces stream to the sum of its items stream.toSum()
toValue Reduces stream like array.reduce() function stream.toValue(reducer, initialValue)
Summary Terminal Operations
Terminal Operation Description Code Snippet
allMatch Returns true if all items in stream match predicate stream.allMatch(predicate)
allUnique Returns true if all elements of stream are unique stream.allUnique(predicate)
anyMatch Returns true if any item in stream matches predicate stream.anyMatch(predicate)
exactlyN Returns true if exactly n items are true according to predicate stream.exactlyN(n, predicate)
isReversed Returns true if stream is sorted in reverse descending order stream.isReversed()
isSorted Returns true if stream is sorted in ascending order stream.isSorted()
noneMatch Returns true if none of the items in stream match predicate stream.noneMatch(predicate)
sameWith Returns true if stream and all given collections are the same stream.sameWith(...collections)
sameCountWith Returns true if stream and all given collections have the same lengths stream.sameCountWith(...collections)

Stream Debug Operations

Debug Operation Description Code Snippet
peek Peek at each element between stream operations stream.peek(peekFunc)
peekStream Peek at the entire stream between operations stream.peekStream(peekFunc)

Usage

Multi Iteration

Chain

Chain multiple iterables together into a single continuous sequence.

function* chain<T>(
  ...iterables: Array<Iterable<T> | Iterator<T>>
): Iterable<T>
import { multi } from 'itertools-ts';

const prequels = ['Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith'];
const originals = ['A New Hope', 'Empire Strikes Back', 'Return of the Jedi'];

for (const movie of multi.chain(prequels, originals)) {
  console.log(movie);
}
// 'Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith', 'A New Hope', 'Empire Strikes Back', 'Return of the Jedi'

Zip

Iterate multiple iterable collections simultaneously.

function* zip<T extends Array<Iterable<unknown> | Iterator<unknown>>>(
  ...iterables: T
): Iterable<ZipTuple<T, never>>
import { multi } from 'itertools-ts';

const languages = ['PHP', 'Python', 'Java', 'Go'];
const mascots = ['elephant', 'snake', 'bean', 'gopher'];

for (const [language, mascot] of multi.zip(languages, mascots)) {
  console.log(`The ${language} language mascot is an ${mascot}.`);
}
// The PHP language mascot is an elephant.
// ...

Zip works with multiple iterable inputs - not limited to just two.

import { multi } from 'itertools-ts';

const names          = ['Ryu', 'Ken', 'Chun Li', 'Guile'];
const countries      = ['Japan', 'USA', 'China', 'USA'];
const signatureMoves = ['hadouken', 'shoryuken', 'spinning bird kick', 'sonic boom'];

for (const [name, country, signatureMove] of multi.zip(names, countries, signatureMoves)) {
  const streetFighter = new StreetFighter(name, country, signatureMove);
}

Note: For uneven lengths, iteration stops when the shortest iterable is exhausted.

Zip Filled

Iterate multiple iterable collections simultaneously.

function* zipFilled<T extends Array<Iterable<unknown> | Iterator<unknown>>, F>(
  filler: F,
  ...iterables: T
): Iterable<ZipTuple<T, F>>

For uneven lengths, the exhausted iterables will produce filler value for the remaining iterations.

import { multi } from 'itertools-ts';

const letters = ['A', 'B', 'C'];
const numbers = [1, 2];

for (const [letter, number] of multi.zipFilled('filler', letters, numbers)) {
  // ['A', 1], ['B', 2], ['C', 'filler']
}

Zip Longest

Iterate multiple iterable collections simultaneously.

function* zipLongest<T extends Array<Iterable<unknown> | Iterator<unknown>>>(
  ...iterables: T
): Iterable<ZipTuple<T, undefined>>

For uneven lengths, the exhausted iterables will produce undefined for the remaining iterations.

import { multi } from 'itertools-ts';

const letters = ['A', 'B', 'C'];
const numbers = [1, 2];

for (const [letter, number] of multi.zipLongest(letters, numbers)) {
  // ['A', 1], ['B', 2], ['C', undefined]
}

Zip Equal

Iterate multiple iterable collections with equal lengths simultaneously.

Throws LengthException if lengths are not equal, meaning that at least one iterator ends before the others.

function* zipEqual<T extends Array<Iterable<unknown> | Iterator<unknown>>>(
  ...iterables: T
): Iterable<ZipTuple<T, never>>
import { multi } from 'itertools-ts';

const letters = ['A', 'B', 'C'];
const numbers = [1, 2, 3];

for (const [letter, number] of multi.zipEqual(letters, numbers)) {
    // ['A', 1], ['B', 2], ['C', 3]
}

Single Iteration

Chunkwise

Return elements in chunks of a certain size.

function* chunkwise<T>(
  data: Iterable<T>|Iterator<T>,
  chunkSize: number,
): Iterable<Array<T>>

Chunk size must be at least 1.

import { single } from 'itertools-ts';

const movies = [
    'Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith',
    'A New Hope', 'Empire Strikes Back', 'Return of the Jedi',
    'The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker',
];
const trilogies = [];

for (const trilogy of single.chunkwise(movies, 3)) {
    trilogies.push(trilogy);
}
// [
//     ['Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith'],
//     ['A New Hope', 'Empire Strikes Back', 'Return of the Jedi'],
//     ['The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker]',
// ]

Chunkwise Overlap

Return overlapped chunks of elements.

function* chunkwiseOverlap<T>(
  data: Iterable<T>|Iterator<T>,
  chunkSize: number,
  overlapSize: number,
  includeIncompleteTail: boolean = true,
): Iterable<Array<T>>
  • Chunk size must be at least 1.
  • Overlap size must be less than chunk size.
import { single } from 'itertools-ts';

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

for (const chunk of single.chunkwiseOverlap(numbers, 3, 1)) {
  // [1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10]
}

Compress

Compress an iterable by filtering out data that is not selected.

function* compress<T>(
  data: Iterable<T> | Iterator<T>,
  selectors: Iterable<number|boolean> | Iterator<number|boolean>
): Iterable<T>
import { single } from 'itertools-ts';

const movies = [
  'Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith',
  'A New Hope', 'Empire Strikes Back', 'Return of the Jedi',
  'The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker'
];
const goodMovies = [0, 0, 0, 1, 1, 1, 1, 0, 0];

for (const goodMovie of single.compress(movies, goodMovies)) {
  console.log(goodMovie);
}
// 'A New Hope', 'Empire Strikes Back', 'Return of the Jedi', 'The Force Awakens'

Drop While

Drop elements from the iterable while the predicate function is true.

Once the predicate function returns false once, all remaining elements are returned.

function* dropWhile<T>(
  data: Iterable<T>|Iterator<T>,
  predicate: (item: T) => boolean
): Iterable<T>
import { single } from 'itertools-ts';

const scores    = [50, 60, 70, 85, 65, 90];
const predicate = (x) => x < 70;

for (const score of single.dropWhile(scores, predicate)) {
  console.log(score);
}
// 70, 85, 65, 90

Enumerate

Enumerates elements of given collection.

function* enumerate<T>(data: Iterable<T>|Iterator<T>): Iterable<[number, T]>
import { single } from 'itertools-ts';

const letters = ['a', 'b', 'c', 'd', 'e'];

for (const item of single.enumerate(letters)) {
  // [[0, 'a'], [1, 'b'], [2, 'c'], [3, 'd'], [4, 'e']]
}

Filter

Filter out elements from the iterable only returning elements where the predicate function is true.

function* filter<T>(
  data: Iterable<T>|Iterator<T>,
  predicate: (datum: T) => boolean,
): Iterable<T>
import { single } from 'itertools-ts';

const starWarsEpisodes = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const goodMoviePredicate = (episode) => episode > 3 && episode < 8;

for (const goodMovie of single.filter(starWarsEpisodes, goodMoviePredicate)) {
  console.log(goodMovie);
}
// 4, 5, 6, 7

Flat Map

Map a function only the elements of the iterable and then flatten the results.

function* flatMap<TInput, TOutput>(
  data: Iterable<TInput>|Iterator<TInput>,
  mapper: FlatMapper<TInput, TOutput>,
): Iterable<TOutput>
import { single } from 'itertools-ts';

const data = [1, 2, 3, 4, 5];
const mapper = (item) => [item, -item];

for (number of single.flatMap(data, mapper)) {
  console.log(number);
}
// 1 -1 2 -2 3 -3 4 -4 5 -5

Flatten

Flatten a multidimensional iterable.

function* flatten(
  data: Iterable<unknown>|Iterator<unknown>,
  dimensions: number = Infinity,
): Iterable<unknown>
import { single } from 'itertools-ts';

const multidimensional = [1, [2, 3], [4, 5]];

const flattened = [];
for (const number of single.flatten(multidimensional)) {
    flattened.push(number);
}
// [1, 2, 3, 4, 5]

Group By

Group data by a common data element.

Iterate pairs of group name and collection of grouped items.

function* groupBy<T>(
  data: Iterable<T> | Iterator<T>,
  groupKeyFunction: (item: T) => string,
  itemKeyFunction?: (item: T) => string,
): Iterable<[string, Array<T>] | [string, Record<string, T>]>
  • The groupKeyFunction determines the key to group elements by.
  • The optional itemKeyFunction allows custom indexes within each group member.
  • Collection of grouped items may be an array or an object (depends on presence of itemKeyFunction param).
import { single } from 'itertools-ts';

const cartoonCharacters = [
    ['Garfield', 'cat'],
    ['Tom', 'cat'],
    ['Felix', 'cat'],
    ['Heathcliff', 'cat'],
    ['Snoopy', 'dog'],
    ['Scooby-Doo', 'dog'],
    ['Odie', 'dog'],
    ['Donald', 'duck'],
    ['Daffy', 'duck'],
];

const charactersGroupedByAnimal = {};
for (const [animal, characters] of single.groupBy(cartoonCharacters, (x) => x[1])) {
    charactersGroupedByAnimal[animal] = characters;
}
/*
{
  cat: [
    ['Garfield', 'cat'],
    ['Tom', 'cat'],
    ['Felix', 'cat'],
    ['Heathcliff', 'cat'],
  ],
  dog: [
    ['Snoopy', 'dog'],
    ['Scooby-Doo', 'dog'],
    ['Odie', 'dog'],
  ],
  duck: [
    ['Donald', 'duck'],
    ['Daffy', 'duck'],
  ],
}
*/

Keys

Iterate keys of key-value pairs.

function* keys<TKey, TValue>(
  collection: Iterable<[TKey, TValue]>|Iterator<[TKey, TValue]>,
): Iterable<TKey>
import { single } from 'itertools-ts';

const dict = new Map([['a', 1], ['b', 2], ['c', 3]]);

for (const key of single.keys(dict)) {
  console.log(key);
}
// 'a', 'b', 'c'

Limit

Iterate up to a limit.

Stops even if more data available if limit reached.

function* limit<T>(data: Iterable<T>|Iterator<T>, count: number): Iterable<T>
import { single } from 'itertools-ts';

const matrixMovies = ['The Matrix', 'The Matrix Reloaded', 'The Matrix Revolutions', 'The Matrix Resurrections'];
const limit = 1;

for (const goodMovie of single.limit(matrixMovies, limit)) {
    console.log(goodMovie);
}
// 'The Matrix' (and nothing else)

Map

Map a function onto each element.

function* map<TInput, TOutput>(
  data: Iterable<TInput>|Iterator<TInput>,
  mapper: (datum: TInput) => TOutput,
): Iterable<TOutput>
import { single } from 'itertools-ts';

const grades = [100, 99, 95, 98, 100];
const strictParentsOpinion = (g) => (g === 100) ? 'A' : 'F';

for (const actualGrade of single.map(grades, strictParentsOpinion)) {
  console.log(actualGrade);
}
// A, F, F, F, A

Pairwise

Returns successive overlapping pairs.

Returns empty generator if given collection contains fewer than 2 elements.

function* pairwise<T>(data: Iterable<T>|Iterator<T>): Iterable<Pair<T>>
import { single } from 'itertools-ts';

const friends = ['Ross', 'Rachel', 'Chandler', 'Monica', 'Joey', 'Phoebe'];

for (const [leftFriend, rightFriend] of single.pairwise(friends)) {
  console.log(`${leftFriend} and ${rightFriend}`);
}
// Ross and Rachel, Rachel and Chandler, Chandler and Monica, ...

Repeat

Repeat an item.

function* repeat<T>(item: T, repetitions: number): Iterable<T>
import { single } from 'itertools-ts';

data = 'Beetlejuice';
repetitions = 3;

for (const repeated of single.repeat(data, repetitions)) {
  console.log(repeated);
}
// 'Beetlejuice', 'Beetlejuice', 'Beetlejuice'

Skip

Skip n elements in the iterable after optional offset offset.

function* skip<T>(
  data: Iterable<T> | Iterator<T>,
  count: number,
  offset: number = 0
): Iterable<T>
import { single } from 'itertools-ts';

const movies = [
    'The Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith',
    'A New Hope', 'The Empire Strikes Back', 'Return of the Jedi',
    'The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker'
];

const prequelsRemoved = [];
for (const nonPrequel of Single.skip(movies, 3)) {
  prequelsRemoved.push(nonPrequel);
} // Episodes IV - IX

const onlyTheBest = [];
for (const nonSequel of Single.skip(prequelsRemoved, 3, 3)) {
  onlyTheBest.push(nonSequel);
}
// 'A New Hope', 'The Empire Strikes Back', 'Return of the Jedi'

Slice

Extract a slice of the iterable.

function* slice<T>(
  data: Iterable<T>|Iterator<T>,
  start: number = 0,
  count?: number,
  step: number = 1,
): Iterable<T>
import { single } from 'itertools-ts';

const olympics = [1992, 1994, 1996, 1998, 2000, 2002, 2004, 2006, 2008, 2010, 2012, 2014, 2016, 2018, 2020, 2022];
const winterOlympics = [];

for (const winterYear of single.slice(olympics, 1, 8, 2)) {
    winterOlympics.push(winterYear);
}
// [1994, 1998, 2002, 2006, 2010, 2014, 2018, 2022]

Sort

Iterate the collection sorted.

function* sort<T>(
  data: Iterable<T> | Iterator<T>,
  comparator?: Comparator<T>,
): Iterable<T>

Uses default sorting if optional comparator function not provided.

import { single } from 'itertools-ts';

const data = [3, 4, 5, 9, 8, 7, 1, 6, 2];

for (const datum of single.sort(data)) {
  console.log(datum);
}
// 1, 2, 3, 4, 5, 6, 7, 8, 9

Take While

Return elements from the iterable as long as the predicate is true.

Stops iteration as soon as the predicate returns false, even if other elements later on would eventually return true (different from filterTrue).

function* takeWhile<T>(
  data: Iterable<T> | Iterator<T>,
  predicate: (item: T) => boolean
): Iterable<T>
import { single } from 'itertools-ts';

const prices = [0, 0, 5, 10, 0, 0, 9];
const isFree = (price) => price == 0;

for (const freePrice of single.takeWhile(prices, isFree)) {
  console.log(freePrice);
}
// 0, 0

Values

Iterate values of key-value pairs.

function* values<TKey, TValue>(
  collection: Iterable<[TKey, TValue]>|Iterator<[TKey, TValue]>,
): Iterable<TValue>
import { single } from 'itertools-ts';

const dict = new Map([['a', 1], ['b', 2], ['c', 3]]);

for (const value of single.keys(dict)) {
  console.log(value);
}
// 1, 2, 3

Infinite Iteration

Count

Count sequentially forever.

function* count(start: number = 1, step: number = 1): Iterable<number>
import { infinite } from 'itertools-ts';

for (const i of infinite.count()) {
  console.log(i);
}
// 1, 2, 3, 4, 5, ...

Cycle

Cycle through the elements of a collection sequentially forever.

function* cycle<T>(iterable: Iterable<T> | Iterator<T>): Iterable<T>
import { infinite } from 'itertools-ts';

for (const item of infinite.cycle(['rock', 'paper', 'scissors'])) {
  console.log(item);
}
// 'rock', 'paper', 'scissors', 'rock', 'paper', 'scissors', 'rock', ...

Repeat

Repeat an item forever.

function* repeat<T>(item: T): Iterable<T>
import { infinite } from 'itertools-ts';

for (const item of infinite.repeat('bla')) {
  console.log(item);
}
// bla, bla, bla, bla, bla, ...

Math Iteration

Running Average

Accumulate the running average over a list of numbers.

function* runningAverage<T>(
  numbers: Iterable<T> | Iterator<T>,
  initialValue?: number
): Iterable<number>
import { math } from 'itertools-ts';

const grades = [100, 80, 80, 90, 85];

for (const runningAverage of math.runningAverage(grades)) {
  console.log(runningAverage);
}
// 100, 90, 86.667, 87.5, 87

Running Difference

Accumulate the running difference over a list of numbers.

function* runningDifference<T>(
  numbers: Iterable<T> | Iterator<T>,
  initialValue?: number
): Iterable<number>
import { math } from 'itertools-ts';

const credits = [1, 2, 3, 4, 5];

for (const runningDifference of math.runningDifference(credits)) {
    console.log(runningDifference);
}
// -1, -3, -6, -10, -15

Provide an optional initial value to lead off the running difference.

import { math } from 'itertools-ts';

const dartsScores   = [50, 50, 25, 50];
const startingScore = 501;

for (const runningScore of math.runningDifference(dartsScores, startingScore)) {
  console.log(runningScore);
}
// 501, 451, 401, 376, 326

Running Max

Accumulate the running maximum over a list of numbers.

function* runningMax<T>(
  numbers: Iterable<T> | Iterator<T>,
  initialValue?: number
): Iterable<number>
import { math } from 'itertools-ts';

const numbers = [1, 2, 1, 3, 5];

for (const runningMax of math.runningMax(numbers)) {
  console.log(runningMax);
}
// 1, 2, 2, 3, 5

Running Min

Accumulate the running minimum over a list of numbers.

function* runningMin<T>(
  numbers: Iterable<T> | Iterator<T>,
  initialValue?: number
): Iterable<number>
import { math } from 'itertools-ts';

const numbers = [3, 4, 2, 5, 1];

for (const runningMin of math.runningMin(numbers)) {
    console.log(runningMin);
}
// 3, 3, 2, 2, 1

Running Product

Accumulate the running product over a list of numbers.

function* runningProduct<T>(
  numbers: Iterable<T> | Iterator<T>,
  initialValue?: number
): Iterable<number>
import { math } from 'itertools-ts';

const numbers = [1, 2, 3, 4, 5];

for (const runningProduct of math.runningProduct(numbers)) {
  console.log(runningProduct);
}
// 1, 2, 6, 24, 120

Provide an optional initial value to lead off the running product.

import { math } from 'itertools-ts';

const numbers = [1, 2, 3, 4, 5];
const initialValue = 5;

for (const runningProduct of math.runningProduct(numbers, initialValue)) {
  console.log(runningProduct);
}
// 5, 5, 10, 30, 120, 600

Running Total

Accumulate the running total over a list of numbers.

function* runningTotal<T>(
  numbers: Iterable<T> | Iterator<T>,
  initialValue?: number
): Iterable<number>
import { math } from 'itertools-ts';

const prices = [1, 2, 3, 4, 5];

for (const runningTotal of math.runningTotal(prices)) {
    console.log(runningTotal);
}
// 1, 3, 6, 10, 15

Provide an optional initial value to lead off the running total.

import { math } from 'itertools-ts';

const prices = [1, 2, 3, 4, 5];
const initialValue = 5;

for (const runningTotal of math.runningTotal(prices, initialValue)) {
  console.log(runningTotal);
}
// 5, 6, 8, 11, 15, 20

Reduce

To Average

Reduces to the mean average.

Returns undefined if collection is empty.

function toAverage(
  data: Iterable<number> | Iterator<number>,
): number | undefined
import { reduce } from 'itertools-ts';

const grades = [100, 90, 95, 85, 94];

const finalGrade = reduce.toAverage(numbers);
// 92.8

To Count

Reduces iterable to its length.

function toCount(data: Iterable<unknown>|Iterator<unknown>): number
import { reduce } from 'itertools-ts';

const data = [1, 2, 3];

const length = reduce.toCount(data);
// 3

To First

Reduces iterable to its first element.

function toFirst<T>(data: Iterable<T> | Iterator<T>): T

Throws LengthException if collection is empty.

import { reduce } from 'itertools-ts';

const medals = ['gold', 'silver', 'bronze'];

const first = reduce.toFirst(medals);
// gold

To First And Last

Reduces iterable to its first and last elements.

function toFirstAndLast<T>(data: Iterable<T> | Iterator<T>): [T, T]

Throws LengthException if collection is empty.

import { reduce } from 'itertools-ts';

const medals = ['gold', 'silver', 'bronze'];

const result = reduce.toFirstAndLast(medals);
// [gold, bronze]

To Last

Reduces iterable to its last element.

function toLast<T>(data: Iterable<T> | Iterator<T>): T

Throws LengthException if collection is empty.

import { reduce } from 'itertools-ts';

const medals = ['gold', 'silver', 'bronze'];

const first = reduce.toFirst(medals);
// bronze

To Max

Reduces to the max value.

function toMax<TValue>(
  data: Iterable<TValue>|Iterator<TValue>,
  compareBy?: (datum: TValue) => Comparable,
): TValue|undefined
  • Optional callable param compareBy must return comparable value.
  • If compareBy is not provided then items of given collection must be comparable.
  • Returns undefined if collection is empty.
import { reduce } from 'itertools-ts';

const numbers = [5, 3, 1, 2, 4];

const result = reduce.toMax(numbers);
// 1

const movieRatings = [
  {
    title: 'The Matrix',
    rating: 4.7,
  },
  {
    title: 'The Matrix Reloaded',
    rating: 4.3,
  },
  {
    title: 'The Matrix Revolutions',
    rating: 3.9,
  },
  {
    title: 'The Matrix Resurrections',
    rating: 2.5,
  },
];
const compareBy = (movie) => movie.rating;

const lowestRatedMovie = reduce.toMin(movieRatings, compareBy);
// {
//   title: 'The Matrix',
//   rating: 4.7,
// }

To Min

Reduces to the min value.

function toMin<TValue>(
  data: Iterable<TValue>|Iterator<TValue>,
  compareBy?: (datum: TValue) => Comparable,
): TValue|undefined
  • Optional callable param compareBy must return comparable value.
  • If compareBy is not provided then items of given collection must be comparable.
  • Returns undefined if collection is empty.
import { reduce } from 'itertools-ts';

const numbers = [5, 3, 1, 2, 4];

const result = reduce.toMin(numbers);
// 1

const movieRatings = [
  {
    title: 'The Matrix',
    rating: 4.7,
  },
  {
    title: 'The Matrix Reloaded',
    rating: 4.3,
  },
  {
    title: 'The Matrix Revolutions',
    rating: 3.9,
  },
  {
    title: 'The Matrix Resurrections',
    rating: 2.5,
  },
];
const compareBy = (movie) => movie.rating;

const lowestRatedMovie = reduce.toMin(movieRatings, compareBy);
// {
//   title: 'The Matrix Resurrections',
//   rating: 2.5,
// }

To Min Max

Reduces collection to its lower and upper bounds.

function toMinMax<T>(
  data: Iterable<T> | Iterator<T>,
  compareBy?: (item: T) => Comparable
): [T?, T?]
  • Optional callable param compareBy must return comparable value.
  • If compareBy is not provided then items of given collection must be comparable.
  • Returns [undefined, undefined] if collection is empty.
import { reduce } from 'itertools-ts';

const numbers = [5, 3, 1, 2, 4];

const result = reduce.toMinMax(numbers);
// [1, 5]

const movieRatings = [
  {
    title: 'The Matrix',
    rating: 4.7,
  },
  {
    title: 'The Matrix Reloaded',
    rating: 4.3,
  },
  {
    title: 'The Matrix Revolutions',
    rating: 3.9,
  },
  {
    title: 'The Matrix Resurrections',
    rating: 2.5,
  },
];
const compareBy = (movie) => movie.rating;

const lowestRatedMovie = reduce.toMin(movieRatings, compareBy);
// [{
//   title: 'The Matrix Resurrections',
//   rating: 2.5,
// },
// {
//   title: 'The Matrix',
//   rating: 4.7,
// }]

To Product

Reduces to the product of its elements.

Returns undefined if collection is empty.

function toProduct(data: Iterable<number>|Iterator<number>): number|undefined
import { reduce } from 'itertools-ts';

const primeFactors = [5, 2, 2];

const number = reduce.toProduct(primeFactors);
// 20

To Range

Reduces given collection to its range (difference between max and min).

function toRange(numbers: Iterable<number|string> | Iterator<number|string>): number

Returns 0 if iterable source is empty.

import { reduce } from 'itertools-ts';

const grades = [100, 90, 80, 85, 95];

const range = reduce.toRange(numbers);
// 20

To Sum

Reduces to the sum of its elements.

function toSum(data: Iterable<number>|Iterator<number>): number
import { reduce } from 'itertools-ts';

const parts = [10, 20, 30];

const sum = reduce.toSum(parts);
// 60

To Value

Reduce elements to a single value using reducer function.

function toValue<TInput, TOutput>(
  data: Iterable<TInput>|Iterator<TInput>,
  reducer: (carry: TOutput|undefined, datum: TInput) => TOutput,
  initialValue?: TOutput,
): TOutput|undefined
import { reduce } from 'itertools-ts';

const input = [1, 2, 3, 4, 5];
const sum = (carry, item) => carry + item;

const result = reduce.toValue(input, sum, 0);
// 15

Set and multiset

Cartesian Product

Iterates cartesian product of given iterables.

function* cartesianProduct<T extends Array<Iterable<unknown> | Iterator<unknown>>>(
  ...iterables: T
): Iterable<ZipTuple<T, never>>
import { set } from 'itertools-ts';

const numbers = [1, 2];
const letters = ['a', 'b'];
const chars = ['!', '?'];

for (const tuple of set.cartesianProduct(numbers, letters, chars)) {
  console.log(tuple);
}
/*
  [1, 'a', '!'],
  [1, 'a', '?'],
  [1, 'b', '!'],
  [1, 'b', '?'],
  [2, 'a', '!'],
  [2, 'a', '?'],
  [2, 'b', '!'],
  [2, 'b', '?'],
*/

Distinct

Filter out elements from the iterable only returning distinct elements.

function* distinct<T>(
  data: Iterable<T>|Iterator<T>,
  compareBy?: (datum: T) => Comparable
): Iterable<T>

Always treats different instances of objects and arrays as unequal.

import { set } from 'itertools-ts';

const chessSet = ['rook', 'rook', 'knight', 'knight', 'bishop', 'bishop', 'king', 'queen', 'pawn', 'pawn'];

for (const chessPiece of set.distinct(chessSet)) {
  console.log(chessPiece);
}
// rook, knight, bishop, king, queen, pawn


const users = [
  { 'name': 'John', 'id': 1 },
  { 'name': 'Mary', 'id': 2 },
  { 'name': 'Mary', 'id': 3 },
  { 'name': 'John', 'id': 4 },
  { 'name': 'Jane', 'id': 5 },
];

for (const user of set.distinct(users, (item) => item['name'])) {
  console.log(user);
}
// { 'name': 'John', 'id': 1 }, { 'name': 'Mary', 'id': 2 }, { 'name': 'Jane', 'id': 5 }

Intersection

Iterates intersection of iterables.

function* intersection<T>(...iterables: Array<Iterable<T> | Iterator<T>>): Iterable<T>
  • Always treats different instances of objects and arrays as unequal.
  • If input iterables produce duplicate items, then multiset intersection rules apply.
import { set } from 'itertools-ts';

const chessPieces = ['rook', 'knight', 'bishop', 'queen', 'king', 'pawn'];
const shogiPieces = ['rook', 'knight', 'bishop', 'king', 'pawn', 'lance', 'gold general', 'silver general'];

for (const commonPiece of set.intersection(chessPieces, shogiPieces)) {
    console.log(commonPiece);
}
// rook, knight, bishop, king, pawn

Partial Intersection

Iterates M-partial intersection of iterables.

function* partialIntersection<T>(
  minIntersectionCount: number,
  ...iterables: Array<Iterable<T> | Iterator<T>>
): Iterable<T>
  • Always treats different instances of objects and arrays as unequal.
  • If input iterables produce duplicate items, then multiset intersection rules apply.
import { set } from 'itertools-ts';

const staticallyTyped    = ['c++', 'java', 'c#', 'go', 'haskell'];
const dynamicallyTyped   = ['php', 'python', 'javascript', 'typescript'];
const supportsInterfaces = ['php', 'java', 'c#', 'typescript'];

for (const language of set.partialIntersection(2, staticallyTyped, dynamicallyTyped, supportsInterfaces)) {
    console.log(language);
}
// c++, java, c#, go, php

Symmetric difference

Iterates the symmetric difference of iterables.

function* symmetricDifference<T>(
  ...iterables: Array<Iterable<T> | Iterator<T>>
): Iterable<T>
  • Always treats different instances of objects and arrays as unequal.
  • If input iterables produce duplicate items, then multiset difference rules apply.
import { set } from 'itertools-ts';

const a = [2, 3, 4, 7];
const b = [2, 3, 5, 8];
const c = [2, 3, 6, 9];

for (const item of set.symmetricDifference(a, b, c)) {
  console.log(item);
}
// 4, 5, 6, 7, 8, 9

Union

Iterates the union of iterables.

function* union<T>(...iterables: Array<Iterable<T> | Iterator<T>>): Iterable<T>
  • Always treats different instances of objects and arrays as unequal.
  • If input iterables produce duplicate items, then multiset difference rules apply.
import { set } from 'itertools-ts';

const a = [1, 2, 3];
const b = [2, 3, 4];
const c = [3, 4, 5];

for (const item of set.symmetricDifference(a, b, c)) {
    console.log(item);
}
// 1, 2, 3, 4, 5

Summary

All Match

Returns true if all elements match the predicate function.

function allMatch<T>(
  data: Iterable<T> | Iterator<T>,
  predicate: (item: T) => boolean
): boolean

Empty collections return true.

import { summary } from "itertools-ts";

const finalFantasyNumbers = [4, 5, 6];
const isOnSuperNintendo   = (ff) => ff >= 4 && ff <= 6;

const trueResult = summary.allMatch(finalFantasyNumbers, isOnSuperNintendo);
// true

const isOnPlaystation = (ff) => ff >= 7 && ff <= 9;

const falseResult = summary.allMatch(finalFantasyNumbers, isOnPlaystation);
// false

All Unique

Return true if all elements in given collection are unique.

function allUnique(data: Iterable<unknown> | Iterator<unknown>): boolean

Empty collections return true.

Considers different instances of data containers to be different, even if they have the same content.

import { summary } from "itertools-ts";

const uniqueNumbers = [1, 2, 3, 4, 5];
summary.allUnique(uniqueNumbers);
// true

const notUniqueNumbers = [1, 1, 2, 2, 3];
summary.allUnique(notUniqueNumbers);
// false

Any Match

Returns true if any element matches the predicate function.

function anyMatch<T>(
  data: Iterable<T> | Iterator<T>,
  predicate: (item: T) => boolean
): boolean

Empty collections return false.

import { summary } from "itertools-ts";

const answers          = ['fish', 'towel', 42, "don't panic"];
const isUltimateAnswer = (a) => a == 42;

const trueResult = summary.anyMatch(answers, isUltimateAnswer);
// true

Exactly N

Returns true if exactly n items are true according to a predicate function.

  • Predicate is optional.
  • Default predicate is boolean value of each item.
function exactlyN<T>(
  data: Iterable<T> | Iterator<T>,
  n: number,
  predicate?: (item: T) => boolean,
): boolean
import { summary } from "itertools-ts";

const twoTruthsAndALie = [true, true, false];
const n = 2;

const trueResult = summary.exactlyN(twoTruthsAndALie, n);
// true

const ages = [18, 21, 24, 54];
const m = 4;
const predicate = (age) => age >= 21;

const falseResult = Summary::exactlyN(ages, m, predicate);
// false

Is Async Iterable

Returns true if given data is an AsyncIterable instance.

function isAsyncIterable(input: unknown): boolean
import { summary } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

summary.isIterable(input); // false
summary.isIterable(input[Symbol.asyncIterator]()) // false
summary.isIterable(1); // false

Is Iterable

Returns true if given data is an Iterable instance.

function isIterable(input: unknown): boolean
import { summary } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

summary.isIterable(input); // true
summary.isIterable(input[Symbol.iterator]()) // false
summary.isIterable(1); // false

Is Iterator

Returns true if given data is an Iterator instance.

function isIterator(input: unknown): boolean
import { summary } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

summary.isIterator(input[Symbol.iterator]()) // true
summary.isIterator(input); // false
summary.isIterator(1); // false

Is Reversed

Returns true if elements are reverse sorted, otherwise false.

function isReversed(data: Iterable<Comparable> | Iterator<Comparable>): boolean
  • Elements must be comparable.
  • Returns true if empty or has only one element.
import { summary } from "itertools-ts";

const reversedNumbers = [5, 4, 3, 2, 1];

Summary.isReversed(reversedNumbers);
// true

const numbers = [1, 4, 3, 2, 1];

Summary.isReversed(numbers);
// false

Is Sorted

Returns true if elements are sorted, otherwise false.

function isSorted(data: Iterable<Comparable> | Iterator<Comparable>): boolean
  • Elements must be comparable.
  • Returns true if empty or has only one element.
import { summary } from "itertools-ts";

const sortedNumbers = [1, 2, 3, 4, 5];

Summary.isSorted(sortedNumbers);
// true

const numbers = [3, 2, 3, 4, 5];

Summary.isSorted(numbers);
// false

Is String

Returns true if given data is a string.

function isString(input: unknown): boolean
import { summary } from "itertools-ts";

summary.isString('') // true
summary.isString('abc') // true
summary.isString(String('abc')) // true
summary.isString(1); // false

None Match

Returns true if no element matches the predicate function.

function noneMatch<T>(
  data: Iterable<T> | Iterator<T>,
  predicate: (item: T) => boolean
): boolean

Empty collections return true.

import { summary } from "itertools-ts";

const grades         = [45, 50, 61, 0];
const isPassingGrade = (grade) => grade >= 70;

const trueResult = summary.noneMatch(grades, isPassingGrade);
// true

Same

Returns true if all given collections are the same.

For single collection or empty collections list returns true.

function same(...collections: Array<Iterable<unknown> | Iterator<unknown>>): boolean
import { summary } from "itertools-ts";

const cocaColaIngredients = ['carbonated water', 'sugar', 'caramel color', 'phosphoric acid'];
const pepsiIngredients    = ['carbonated water', 'sugar', 'caramel color', 'phosphoric acid'];
const spriteIngredients   = ['carbonated water', 'sugar', 'citric acid', 'lemon lime flavorings'];

const trueResult = summary.same(cocaColaIngredients, pepsiIngredients);
// true

const falseResult = summary.same(cocaColaIngredients, spriteIngredients);
// false

Same Count

Returns true if all given collections have the same lengths.

For single collection or empty collections list returns true.

function same(
  ...collections: Array<Iterable<unknown> | Iterator<unknown>>
): boolean
import { summary } from "itertools-ts";

const prequels  = ['Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith'];
const originals = ['A New Hope', 'Empire Strikes Back', 'Return of the Jedi'];
const sequels   = ['The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker'];

const trueResult = summary.sameCount(prequels, originals, sequels);
// true

const batmanMovies = ['Batman Begins', 'The Dark Knight', 'The Dark Knight Rises'];
const matrixMovies = ['The Matrix', 'The Matrix Reloaded', 'The Matrix Revolutions', 'The Matrix Resurrections'];

const falseResult = summary.sameCount(batmanMovies, matrixMovies);
// false

Transform

Tee

Return several independent (duplicated) iterators from a single iterable.

function tee<T>(
  collection: Iterable<T> | Iterator<T>,
  count: number
): Array<RelatedIterable<T>>

Once tee has been called to duplicate iterators, it is advisable to not use the original input iterator any further.

Duplicating iterators can use up memory. Consider if tee is the right solution. For example, arrays and most iterators can be rewound and reiterated without need for duplication.

import { transform } from "itertools-ts";

const daysOfWeek = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'];
const count = 3;

const [week1, week2, week3] = transform.tee(data, count);
// Each week contains iterator containing ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun']

To Array

Returns Array instance of given collection or iterator.

function toArray<T>(
  collection: Iterable<T>|Iterator<T>
): Array<T>
import { transform } from "itertools-ts";

const iterator = transform.toIterator([1, 2, 3, 4, 5]);

const result = transform.toArray(iterator);
// [1, 2, 3, 4, 5]

To Async Iterable

Returns AsyncIterable instance of given collection, record or iterator (sync or async).

Throws InvalidArgumentError if given data is not a collection or an iterator.

function toAsyncIterable<T>(
  collection:
    | Iterable<T>
    | Iterator<T>
    | AsyncIterable<T>
    | AsyncIterator<T>
    | Record<RecordKey, unknown>
): AsyncIterable<T>
import { transform } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = transform.toAsyncIterable(input);
// AsyncIterable<[1, 2, 3, 4, 5]>

To Async Iterator

Returns AsyncIterator instance of given collection or iterator.

Throws InvalidArgumentError if given data is not a collection or an iterator.

function toAsyncIterator<T>(
  collection: Iterable<T> | Iterator<T> | AsyncIterable<T> | AsyncIterator<T>
): AsyncIterator<T>
import { transform } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = transform.toAsyncIterator(input);
console.log(result.next !== undefined);
// true

To Iterable

Returns Iterable instance of given collection, record or iterator.

Throws InvalidArgumentError if given data is not a collection or an iterator.

function toIterable<T>(
  collection: Iterable<T>|Iterator<T>|Record<string|number|symbol, unknown>
): Iterable<T>
import { transform } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = transform.toIterable(input);
// [1, 2, 3, 4, 5]

To Iterator

Returns Iterator instance of given collection or iterator.

Throws InvalidArgumentError if given data is not a collection or an iterator.

function toIterator<T>(collection: Iterable<T>|Iterator<T>): Iterator<T>
import { transform } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = transform.toIterator(input);
console.log(result.next !== undefined);
// true

To Map

Converts given iterable of key-value pairs to Map.

function toMap<TKey, TValue>(
  pairs: Iterable<[TKey, TValue]> | Iterator<[TKey, TValue]> | Record<string|number|symbol, unknown>
): Map<TKey, TValue>
import { transform } from "itertools-ts";

const input = [['a', 1], ['b', 2], ['c', 3]];

const result = transform.toMap(input);
// Map([['a', 1], ['b', 2], ['c', 3]])

To Set

Converts given iterable to Set.

function toSet<T>(
  collection: Iterable<T> | Iterator<T>
): Set<T>
import { transform } from "itertools-ts";

const input = [1, 1, 2, 2, 3, 3];

const result = transform.toSet(input);
// Set([1, 2, 3])

Stream and Async Stream

Streams provide a fluent interface to transform arrays and iterables (sync or async) through a pipeline of operations.

Streams are made up of:

  1. One stream source factory method to create the stream.
  2. Zero or more stream operators that transform the stream to a new stream.
  3. Terminal operation of either:
    • Stream terminal operation to transform the stream to a value or data structure.
      const result1 = Stream.of([1, 1, 2, 2, 3, 4, 5])
        .distinct()             // [1, 2, 3, 4, 5]
        .map((x) => x**2)       // [1, 4, 9, 16, 25]
        .filter((x) => x < 10)  // [1, 4, 9]
        .toSum();               // 14
      
      // Async example
      const result2 = await AsyncStream.of([1, 1, 2, 2, 3, 4, 5].map((x) => Promise.resolve(x)))
        .distinct()             // [1, 2, 3, 4, 5]
        .map((x) => x**2)       // [1, 4, 9, 16, 25]
        .filter((x) => x < 10)  // [1, 4, 9]
        .toSum();               // 14
    • The stream is iterated via a for loop.
      const result1 = Stream.of([1, 1, 2, 2, 3, 4, 5])
        .distinct()             // [1, 2, 3, 4, 5]
        .map((x) => x**2)       // [1, 4, 9, 16, 25]
        .filter((x) => x < 10); // [1, 4, 9]
      
      for (const item of result1) {
        // 1, 4, 9
      }
      
      // Async example
      const result2 = AsyncStream.of([1, 1, 2, 2, 3, 4, 5].map((x) => Promise.resolve(x)))
        .distinct()             // [1, 2, 3, 4, 5]
        .map((x) => x**2)       // [1, 4, 9, 16, 25]
        .filter((x) => x < 10); // [1, 4, 9]
      
      for await (const item of result2) {
        // 1, 4, 9
      }

Stream Sources

Of

Creates stream from an iterable.

Stream.of(data: Iterable<unknown>|Iterator<unknown>): Stream
import { Stream } from "itertools-ts";

const iterable = [1, 2, 3];

const result = Stream.of(iterable)
  .chainWith([4, 5, 6], [7, 8, 9])
  .zipEqualWith([1, 2, 3, 4, 5, 6, 7, 8, 9])
  .toArray();
// [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9]]

Of Empty

Creates stream of nothing.

Stream.ofEmpty(): Stream
import { Stream } from "itertools-ts";

const result = Stream.ofEmpty()
  .chainWith([1, 2, 3])
  .toArray();
// [1, 2, 3]

Of Count

Create an infinite count stream.

Stream.ofCount(start: number = 1, step: number = 1): Stream
import { Stream } from "itertools-ts";

const result = Stream.ofCount(0, 10)
  .limit(5)
  .toArray();
// [0, 10, 20, 30, 40]

Of Cycle

Create an infinite cycle stream.

Stream.ofCycle(iterable: Iterable<unknown> | Iterator<unknown>): Stream
import { Stream } from "itertools-ts";

const result = Stream.ofCycle([1, 2, 3])
  .limit(7)
  .toArray();
// [1, 2, 3, 1, 2, 3, 1]

Of Repeat

Create an infinite stream repeating given item.

Stream.ofRepeat(item: unknown): Stream
import { Stream } from "itertools-ts";

const result = Stream.ofRepeat('bla')
  .limit(5)
  .toArray();
// [bla, bla, bla, bla, bla]

Stream Operations

Cartesian Product With

Iterate cartesian product of iterable source with another iterable collections.

stream.cartesianProductWith(
  ...iterables: Array<Iterable<unknown> | Iterator<unknown>>
): Stream
import { Stream } from "itertools-ts";

const numbers = [1, 2];

const result = Stream.of(numbers)
  .cartesianProductWith(['a', 'b'], ['!', '?'])
  .toArray();
/*
[
  [1, 'a', '!'],
  [1, 'a', '?'],
  [1, 'b', '!'],
  [1, 'b', '?'],
  [2, 'a', '!'],
  [2, 'a', '?'],
  [2, 'b', '!'],
  [2, 'b', '?'],
]
*/

Chain With

Return a stream chaining additional sources together into a single consecutive stream.

stream.chainWith(
  ...iterables: Array<Iterable<unknown>|Iterator<unknown>>
): Stream
import { Stream } from "itertools-ts";

const input = [1, 2, 3];

const result = Stream.of(input)
  .chainWith([4, 5, 6])
  .chainWith([7, 8, 9])
  .toArray();
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

Chunkwise

Return a stream consisting of chunks of elements from the stream.

stream.chunkwise(chunkSize: number): Stream

Chunk size must be at least 1.

import { Stream } from "itertools-ts";

const friends = ['Ross', 'Rachel', 'Chandler', 'Monica', 'Joey'];

const result = Stream.of(friends)
  .chunkwise(2)
  .toArray();
// [['Ross', 'Rachel'], ['Chandler', 'Monica'], ['Joey']]

Chunkwise Overlap

Return a stream consisting of overlapping chunks of elements from the stream.

stream.chunkwiseOverlap(
  chunkSize: number,
  overlapSize: number,
  includeIncompleteTail: boolean = true,
): Stream
  • Chunk size must be at least 1.
  • Overlap size must be less than chunk size.
import { Stream } from "itertools-ts";

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];

const result = Stream.of(numbers)
  .chunkwiseOverlap(3, 1)
  .toArray()
// [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]]

Compress

Compress to a new stream by filtering out data that is not selected.

stream.compress(selectors: Iterable<number|boolean> | Iterator<number|boolean>): Stream

Selectors indicate which data. True value selects item. False value filters out data.

import { Stream } from "itertools-ts";

const input = [1, 2, 3];

const result = Stream.of(input)
  .compress([0, 1, 1])
  .toArray();
// [2, 3]

Distinct

Return a stream filtering out elements from the stream only returning distinct elements.

stream.distinct(compareBy?: (datum: unknown) => Comparable): Stream
import { Stream } from "itertools-ts";

const input = [1, 2, 1, 2, 3, 3, '1', '1', '2', '3'];
const numbers = Stream.of(input)
  .distinct()
  .toArray();
// [1, 2, 3, '1', '2', '3']

const users = [
  { 'name': 'John', 'id': 1 },
  { 'name': 'Mary', 'id': 2 },
  { 'name': 'Mary', 'id': 3 },
  { 'name': 'John', 'id': 4 },
  { 'name': 'Jane', 'id': 5 },
];
const result = Stream.of(input)
  .distinct((item) => item['name'])
  .toArray();
/*
[
  { 'name': 'John', 'id': 1 },
  { 'name': 'Mary', 'id': 2 },
  { 'name': 'Jane', 'id': 5 },
]
*/

Drop While

Drop elements from the stream while the predicate function is true.

stream.dropWhile(predicate: (item: unknown) => boolean): Stream

Once the predicate function returns false once, all remaining elements are returned.

import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5]

const result = Stream.of(input)
  .dropWhile((value) => value < 3)
  .toArray();
// [3, 4, 5]

Enumerate

Enumerates elements of the stream.

stream.enumerate(): Stream
import { Stream } from "itertools-ts";

const input = ['a', 'b', 'c', 'd', 'e'];
const stream = Stream.of(input)
  .enumerate()
  .toArray();
// [[0, 'a'], [1, 'b'], [2, 'c'], [3, 'd'], [4, 'e']]

Filter

Filter out elements from the stream only keeping elements where there predicate function is true.

stream.filter(predicate: (item: unknown) => boolean): Stream
import { Stream } from "itertools-ts";

const input = [1, -1, 2, -2, 3, -3];

const result = Stream.of(input)
  .filter((value) => value > 0)
  .toArray();
// [1, 2, 3]

Flat Map

Map a function onto the elements of the stream and flatten the results.

stream.flatMap(mapper: (datum: unknown) => unknown): Stream
import { Stream } from "itertools-ts";

const data = [1, 2, 3, 4, 5];
const mapper = (item) => (item % 2 === 0) ? [item, item] : item;

const result = Stream.of(data)
  .flatMap(mapper)
  .toArray();
// [1, 2, 2, 3, 4, 4, 5]

Flatten

Flatten a multidimensional stream.

stream.flatten(dimensions: number = Infinity): Stream
import { Stream } from "itertools-ts";

const data = [1, [2, 3], [4, 5]];

const result = Stream.of(data)
  .flatten()
  .toArray();
// [1, 2, 3, 4, 5]

Intersection With

Return a stream intersecting the stream with the input iterables.

stream.intersectionWith(...iterables: Array<Iterable<unknown> | Iterator<unknown>>): Stream
  • Always treats different instances of objects and arrays as unequal.
  • If input iterables produce duplicate items, then multiset intersection rules apply.
import { Stream } from 'itertools-ts';

const chessPieces = ['rook', 'knight', 'bishop', 'queen', 'king', 'pawn'];
const shogiPieces = ['rook', 'knight', 'bishop', 'king', 'pawn', 'lance', 'gold general', 'silver general'];

const result = Stream.of(chessPieces)
  .intersectionWith(shogiPieces)
  .toArray();
// [rook, knight, bishop, king, pawn]

Group By

Group stream data by a common data element.

Iterate pairs of group name and collection of grouped items.

stream.groupBy(
  groupKeyFunction: (item: unknown) => string,
  itemKeyFunction?: (item: unknown) => string,
): Stream
  • The groupKeyFunction determines the key to group elements by.
  • The optional itemKeyFunction allows custom indexes within each group member.
  • Collection of grouped items may be an array or an object (depends on presence of itemKeyFunction param).
import { Stream } from 'itertools-ts';

const cartoonCharacters = [
    ['Garfield', 'cat'],
    ['Tom', 'cat'],
    ['Felix', 'cat'],
    ['Heathcliff', 'cat'],
    ['Snoopy', 'dog'],
    ['Scooby-Doo', 'dog'],
    ['Odie', 'dog'],
    ['Donald', 'duck'],
    ['Daffy', 'duck'],
];

const result = Stream.of(cartoonCharacters)
  .groupBy((x) => x[1])
  .toArray();
/*
[
  ['cat', [
    ['Garfield', 'cat'],
    ['Tom', 'cat'],
    ['Felix', 'cat'],
    ['Heathcliff', 'cat'],
  ]],
  ['dog', [
    ['Snoopy', 'dog'],
    ['Scooby-Doo', 'dog'],
    ['Odie', 'dog'],
  ]],
  ['duck', [
    ['Donald', 'duck'],
    ['Daffy', 'duck'],
  ]],
]
*/

Keys

Iterate keys of key-value pairs.

stream.keys(): Stream
import { Stream } from 'itertools-ts';

const dict = new Map([['a', 1], ['b', 2], ['c', 3]]);

const result = Stream.of(dict)
  .keys()
  .toArray();
// ['a', 'b', 'c']

Limit

Return a stream up to a limit.

Stops even if more data available if limit reached.

stream.limit(count: number): Stream
import { Stream } from "itertools-ts";

const matrixMovies = ['The Matrix', 'The Matrix Reloaded', 'The Matrix Revolutions', 'The Matrix Resurrections'];
const limit = 1;

const goodMovies = Stream.of(matrixMovies)
  .limit(limit)
  .toArray();
// ['The Matrix'] (and nothing else)

Map

Return a stream containing the result of mapping a function onto each element of the stream.

stream.map(mapper: (datum: unknown) => unknown): Stream
import { Stream } from "itertools-ts";

const grades = [100, 95, 98, 89, 100];

const result = Stream.of(grades)
  .map((grade) => grade === 100 ? 'A' : 'F')
  .toArray();
// [A, F, F, F, A]

Pairwise

Return a stream consisting of pairs of elements from the stream.

stream.pairwise(): Stream

Returns empty stream if given collection contains less than 2 elements.

import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const stream = Stream.of(input)
  .pairwise()
  .toArray();
// [[1, 2], [2, 3], [3, 4], [4, 5]]

Partial Intersection With

Return a stream partially intersecting the stream with the input iterables.

stream.partialIntersectionWith(
  minIntersectionCount: number,
  ...iterables: Array<Iterable<unknown> | Iterator<unknown>>
): Stream
  • Always treats different instances of objects and arrays as unequal.
  • If input iterables produce duplicate items, then multiset intersection rules apply.
import { Stream } from 'itertools-ts';

const staticallyTyped    = ['c++', 'java', 'c#', 'go', 'haskell'];
const dynamicallyTyped   = ['php', 'python', 'javascript', 'typescript'];
const supportsInterfaces = ['php', 'java', 'c#', 'typescript'];

const result = Stream.of(staticallyTyped)
  .partialIntersectionWith(2, dynamicallyTyped, supportsInterfaces)
  .toArray();
// ['c++', 'java', 'c#', 'go', 'php']

Running Average

Return a stream accumulating the running average (mean) over the stream.

stream.runningAverage(initialValue?: number): Stream
import { Stream } from 'itertools-ts';

const input = [1, 3, 5];

const result = Stream.of(input)
  .runningAverage()
  .toArray();
// [1, 2, 3]

Running Difference

Return a stream accumulating the running difference over the stream.

stream.runningDifference(initialValue?: number): Stream
import { Stream } from 'itertools-ts';

const input = [1, 2, 3, 4, 5];

const result = Stream.of(input)
  .runningDifference()
  .toArray();
// [-1, -3, -6, -10, -15]

Running Max

Return a stream accumulating the running max over the stream.

stream.runningMax(initialValue?: number): Stream
import { Stream } from 'itertools-ts';

const input = [1, -1, 2, -2, 3, -3];

const result = Stream.of(input)
  .runningMax()
  .toArray();
// [1, 1, 2, 2, 3, 3]

Running Min

Return a stream accumulating the running min over the stream.

stream.runningMin(initialValue?: number): Stream
import { Stream } from 'itertools-ts';

const input = [1, -1, 2, -2, 3, -3];

const result = Stream.of(input)
  .runningMin()
  .toArray();
// [1, -1, -1, -2, -2, -3]

Running Product

Return a stream accumulating the running product over the stream.

stream.runningProduct(initialValue?: number): Stream
import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = Stream.of(input)
  .runningProduct()
  .toArray();
// [1, 2, 6, 24, 120]

Running Total

Return a stream accumulating the running total over the stream.

stream.runningTotal(initialValue?: number): Stream
import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = Stream.of(input)
  .runningTotal()
  .toArray();
// [1, 3, 6, 10, 15]

Skip

Skip some elements of the stream.

skip(count: number, offset = 0): Stream
import { Stream } from "itertools-ts";

const movies = [
    'The Phantom Menace', 'Attack of the Clones', 'Revenge of the Sith',
    'A New Hope', 'The Empire Strikes Back', 'Return of the Jedi',
    'The Force Awakens', 'The Last Jedi', 'The Rise of Skywalker'
];

const onlyTheBest = Stream.of(movies)
  .skip(3)
  .skip(3, 3)
  .toArray();
// ['A New Hope', 'The Empire Strikes Back', 'Return of the Jedi']

Slice

Extract a slice of the stream.

stream.slice(start: number = 0, count?: number, step: number = 1): Stream
import { Stream } from "itertools-ts";

const olympics = [1992, 1994, 1996, 1998, 2000, 2002, 2004, 2006, 2008, 2010, 2012, 2014, 2016, 2018, 2020, 2022];

const summerOlympics = Stream.of(olympics)
  .slice(0, 8, 2)
  .toArray();
// [1992, 1996, 2000, 2004, 2008, 2012, 2016, 2020]

Sort

Sorts the stream.

stream.sort(comparator?: Comparator<unknown>): Stream

If comparator is not provided, the elements of the iterable source must be comparable.

import { Stream } from "itertools-ts";

const input = [3, 4, 5, 9, 8, 7, 1, 6, 2];

const result = Stream.of(input)
  .sort()
  .toArray();
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

Symmetric difference With

Return a stream of the symmetric difference of the stream and the given iterables.

stream.symmetricDifferenceWith(...iterables: Array<Iterable<unknown> | Iterator<unknown>>): Stream
  • Always treats different instances of objects and arrays as unequal.
  • If input iterables produce duplicate items, then multiset difference rules apply.
import { Stream } from 'itertools-ts';

const a = [2, 3, 4, 7];
const b = [2, 3, 5, 8];
const c = [2, 3, 6, 9];

const result = Stream.of(a)
  .symmetricDifferenceWith(b, c)
  .toArray();
// [4, 5, 6, 7, 8, 9]

Take While

Keep elements from the stream as long as the predicate is true.

stream.takeWhile(predicate: (item: unknown) => boolean): Stream
import { Stream } from 'itertools-ts';

const input = [1, -1, 2, -2, 3, -3];

const result = Stream.of(input)
  .takeWhile((value) => Math.abs(value) < 3)
  .toArray();
// [1, -1, 2, -2]

Union With

Return a stream of union of the stream with the input iterables.

stream.unionWith(...iterables: Array<Iterable<unknown> | Iterator<unknown>>): Stream
  • Always treats different instances of objects and arrays as unequal.
  • If input iterables produce duplicate items, then multiset difference rules apply.
import { Stream } from 'itertools-ts';

const a = [1, 2, 3];
const b = [2, 3, 4];
const c = [3, 4, 5];

const result = Stream.of(a)
  .unionWith(b, c)
  .toArray();
// [1, 2, 3, 4, 5]

Values

Iterate keys of key-value pairs.

stream.values(): Stream
import { Stream } from 'itertools-ts';

const dict = new Map([['a', 1], ['b', 2], ['c', 3]]);

const result = Stream.of(dict)
  .values()
  .toArray();
// [1, 2, 3]

Zip With

Return a stream consisting of multiple iterable collections streamed simultaneously.

stream.zipWith(
  ...iterables: Array<Iterable<unknown>|Iterator<unknown>>
): Stream

For uneven lengths, iterations stops when the shortest iterable is exhausted.

import { Stream } from "itertools-ts";

const input = [1, 2, 3];

const stream = Stream.of(input)
  .zipWith([4, 5, 6])
  .toArray();
// [[1, 4], [2, 5], [3, 6]]

Zip Equal With

Return a stream consisting of multiple iterable collections of equal lengths streamed simultaneously.

stream.zipEqualWith(
  ...iterables: Array<Iterable<unknown>|Iterator<unknown>>
): Stream

Works like Stream.zipWith() method but throws LengthException if lengths not equal, i.e., at least one iterator ends before the others.

import { Stream } from "itertools-ts";

const input = [1, 2, 3];

const stream = Stream.of(input)
  .zipEqualWith([4, 5, 6]);

for (const zipped of stream) {
    // [1, 4], [2, 5], [3, 6]
}

Zip Filled With

Return a stream consisting of multiple iterable collections streamed simultaneously.

zipFilledWith(
  filler: unknown,
  ...iterables: Array<Iterable<unknown>|Iterator<unknown>>
): Stream
  • Iteration continues until the longest iterable is exhausted.
  • For uneven lengths, the exhausted iterables will produce filler value for the remaining iterations.
import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const stream = Stream.of(input)
  .zipFilledWith('filler', [4, 5, 6]);

for (const zipped of stream) {
  // [1, 4], [2, 5], [3, 6], [4, 'filler'], [5, 'filler']
}

Zip Longest With

Return a stream consisting of multiple iterable collections streamed simultaneously.

stream.zipLongestWith(
  ...iterables: Array<Iterable<unknown>|Iterator<unknown>>
): Stream
  • Iteration continues until the longest iterable is exhausted.
  • For uneven lengths, the exhausted iterables will produce undefined for the remaining iterations.
import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const stream = Stream.of(input)
  .zipLongestWith([4, 5, 6]);

for (const zipped of stream) {
  // [1, 4], [2, 5], [3, 6], [4, undefined], [5, undefined]
}

Terminal operations

Transformation Terminal Operations

Tee

Return several independent (duplicated) streams.

stream.tee(count: number): Array<Stream>
import { Stream } from "itertools-ts";

const daysOfWeek = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'];
const count = 3;

const [week1Stream, week2Stream, week3Stream] = Stream.of(daysOfWeek)
    .tee(count);

// Each weekStream contains ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun']
To Array

Returns an array of stream elements.

stream.toArray(): Array<unknown>
import { Stream } from "itertools-ts";

const result = Stream.of([1, 2, 3, 4, 5])
  .map((x) => x**2)
  .toArray();
// [1, 4, 9, 16, 25]
To Map

Converts stream to Map.

stream.toMap(): Map<unknown, unknown>

Stream collection must contain only key-value pairs as elements.

import { Stream } from "itertools-ts";

const result = Stream.of([1, 2, 3])
  .enumerate()
  .toMap();
// Map([[0, 1], [1, 2], [2, 3]])
To Set

Converts stream to Set.

stream.toSet(): Set<unknown>
import { Stream } from "itertools-ts";

const result = Stream.of([1, 1, 2, 2, 3, 3])
  .toMap();
// Set([1, 2, 3])

Reduce Terminal Operations

To Average

Reduces iterable source to the mean average of its items.

stream.toAverage(): number|undefined

Returns undefined if iterable source is empty.

import { Stream } from "itertools-ts";

const input = [2, 4, 6, 8];

const result = Stream.of(iterable)
  .toAverage();
// 5
To Count

Reduces iterable source to its length.

stream.toCount(): number
import { Stream } from "itertools-ts";

const input = [10, 20, 30, 40, 50];

const result = Stream.of(iterable)
  .toCount();
// 5
To First

Reduces stream to its first element.

stream.toFirst(): unknown

Throws LengthException if stream is empty.

import { Stream } from "itertools-ts";

const input = [10, 20, 30];

const result = Stream.of(input)
  .toFirst();
// 10
To First And Last

Reduces stream to its first last elements.

stream.toFirstAndLast(): [unknown, unknown]

Throws LengthException if stream is empty.

import { Stream } from "itertools-ts";

const input = [10, 20, 30];

const result = Stream.of(input)
  .toFirstAndLast();
// [10, 30]
To Last

Reduces stream to its last element.

stream.toLast(): unknown

Throws LengthException if stream is empty.

import { Stream } from "itertools-ts";

const input = [10, 20, 30];

const result = Stream.of(input)
  .toLast();
// 30
To Max

Reduces stream to its max value.

stream.toMax<TComparable>(compareBy?: (datum: unknown) => TComparable): unknown|undefined
  • Optional callable param compareBy must return comparable value.
  • If compareBy is not provided then items of given collection must be comparable.
  • Returns undefined if collection is empty.
import { Stream } from "itertools-ts";

const input = [1, -1, 2, -2, 3, -3];

const result = Stream.of(iterable)
  .toMax();
// 3
To Min

Reduces stream to its min value.

stream.toMin<TComparable>(compareBy?: (datum: unknown) => TComparable): unknown|undefined
  • Optional callable param compareBy must return comparable value.
  • If compareBy is not provided then items of given collection must be comparable.
  • Returns undefined if collection is empty.
import { Stream } from "itertools-ts";

const input = [1, -1, 2, -2, 3, -3];

const result = Stream.of(iterable)
  .toMin();
// -3
To Min Max

Reduces stream to its min and max values.

toMinMax(compareBy?: (item: unknown) => Comparable): [unknown?, unknown?]
  • Optional callable param compareBy must return comparable value.
  • If compareBy is not provided then items of given collection must be comparable.
  • Returns [undefined, undefined] if collection is empty.
import { Stream } from "itertools-ts";

const input = [1, -1, 2, -2, 3, -3];

const result = Stream.of(iterable)
  .toMinMax();
// [-3, 3]
To Product

Reduces iterable source to the product of its items.

stream.toProduct(): number|undefined

Returns undefined if stream is empty.

import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = Stream.of(input)
  .toProduct();
// 120
To Range

Reduces stream to its range (difference between max and min).

stream.toRange(): number

Returns 0 if iterable source is empty.

import { Stream } from "itertools-ts";

const grades = [100, 90, 80, 85, 95];

const range = stream.of(numbers)
  .toRange();
// 20
To Sum

Reduces iterable source to the sum of its items.

stream.toSum(): number
import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = Stream.of(iterable)
  .toSum();
// 15
To Value

Reduces iterable source like array_reduce() function.

stream.toValue<T>(
  reducer: (carry: T|undefined, datum: unknown) => T,
  initialValue?: T,
): T|undefined
import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const result = Stream.of(input)
  .toValue((carry, item) => carry + item);
// 15

Stream Summary Terminal Operations

All Match

Returns true if all elements of stream match the predicate function.

allMatch(predicate: (item: unknown) => boolean): boolean

For empty stream returns true.

import { Stream } from "itertools-ts";

const finalFantasyNumbers = [4, 5, 6];
const isOnSuperNintendo   = (ff) => ff >= 4 && ff <= 6;

const trueResult = Stream.of(finalFantasyNumbers)
  .allMatch(isOnSuperNintendo);
// true
All Unique

Returns true if all elements in stream are unique.

stream.allUnique(): boolean

Empty collections return true.

Considers different instances of data containers to be different, even if they have the same content.

import { summary } from "itertools-ts";
import { Stream } from './stream';

const uniqueNumbers = [1, 2, 3, 4, 5];
Stream.of(uniqueNumbers)
  .allUnique();
// true

const notUniqueNumbers = [1, 1, 2, 2, 3];
Stream.of(notUniqueNumbers)
  .allUnique();
// false
Any Match

Returns true if any element of stream matches the predicate function.

anyMatch(predicate: (item: unknown) => boolean): boolean

For empty stream returns false.

import { Stream } from "itertools-ts";

const answers          = ['fish', 'towel', 42, "don't panic"];
const isUltimateAnswer = (a) => a == 42;

const trueResult = Stream.of(answers)
  .anyMatch(answers, isUltimateAnswer);
// true
Exactly N

Returns true if exactly n items are true according to a predicate function.

  • Predicate is optional.
  • Default predicate is boolean value of each item.
stream.exactlyN(n: number, predicate?: (item: unknown) => boolean): boolean
import { Stream } from "itertools-ts";
import stream = require("node:stream");

const twoTruthsAndALie = [true, true, false];
const n = 2;

const boolean = stream.of(twoTruthsAndALie)
  .exactlyN(n);
// true
Is Reversed

Returns true if stream is sorted in reverse descending order; otherwise false.

stream.isReversed(): boolean

Items of stream must be comparable.

Returns true if iterable source is empty or has only one element.

import { Stream } from "itertools-ts";

const reversed = [5, 4, 3, 2, 1];

Stream.of(reversed)
  .isReversed();
// true

const input = [1, 2, 3, 2, 1];

Stream.of(input)
  .isReversed();
// false
Is Sorted

Returns true if iterable source is sorted in ascending order; otherwise false.

stream.isSorted(): boolean

Items of iterable source must be comparable.

Returns true if iterable source is empty or has only one element.

import { Stream } from "itertools-ts";

const sorted = [1, 2, 3, 4, 5];

Stream.of(sorted)
  .isSorted();
// true

const input = [1, 2, 3, 2, 1];

Stream.of(input)
  .isSorted();
// false
None Match

Returns true if no element of stream matches the predicate function.

noneMatch(predicate: (item: unknown) => boolean): boolean

For empty stream returns true.

import { Stream } from "itertools-ts";

const grades         = [45, 50, 61, 0];
const isPassingGrade = (grade) => grade >= 70;

const trueResult = Stream.of(grades)
  .noneMatch(isPassingGrade);
// true
Same With

Returns true if stream and all given collections are the same.

sameWith(...collections: Array<Iterable<unknown> | Iterator<unknown>>): boolean

For empty collections list returns true.

import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const trueResult = Stream.of(input)
  .sameWith([1, 2, 3, 4, 5]);
// true

const falseResult = Stream.of(input)
  .sameWith([5, 4, 3, 2, 1]);
// false
Same Count With

Returns true if stream collection and all given collections have the same lengths.

stream.sameCountWith(...collections: Array<Iterable<unknown> | Iterator<unknown>>): boolean

For empty collections list returns true.

import { Stream } from "itertools-ts";

const input = [1, 2, 3, 4, 5];

const trueResult = Stream.of(input)
  .sameCountWith([5, 4, 3, 2, 1]);
// true

const falseResult = Stream.of(input)
  .sameCountWith([1, 2, 3]);
// false

Stream Debug Operations

Peek

Peek at each element between other Stream operations to do some action without modifying the stream.

stream.peek(callback: (datum: unknown) => void): Stream
import { Stream } from "itertools-ts";

const result = Stream.of(['some', 'items'])
  .peek((x) => console.log(x)) // 'some', 'items'
  .toArray();

console.log(result);
// ['some', 'items']

Peek Stream

Peek at the entire stream between other Stream operations to do some action without modifying the stream.

stream.peekStream(callback: (datum: Stream) => void): Stream
import { Stream } from "itertools-ts";

const result = Stream.of(['some', 'items'])
  .peekStream((stream) => console.log(stream.toArray())) // ['some', 'items']
  .toArray();

console.log(result);
// ['some', 'items']

Unit testing

npm i
npm run test

License

IterTools TS is licensed under the MIT License.