Skip to main content
The @temelj/iterator package provides comprehensive utilities for working with iterators, including collection operations, combinatorics, numeric ranges, filtering, searching, and tree traversal.

Installation

npm install @temelj/iterator

Collection operations

collectMap

Collects values from an iterable into a record using a key function.
function collectMap<K extends keyof any, V, V1 = V>(
  it: Iterable<V>,
  getKey: (e: V) => K,
  map?: (e: V) => V1,
): Record<K, V1>
import { collectMap } from "@temelj/iterator";

const users = [
  { id: "1", name: "Alice" },
  { id: "2", name: "Bob" },
];

const userMap = collectMap(users, (u) => u.id);
// Result: { "1": { id: "1", name: "Alice" }, "2": { id: "2", name: "Bob" } }

const nameMap = collectMap(users, (u) => u.id, (u) => u.name);
// Result: { "1": "Alice", "2": "Bob" }

groupBy

Groups elements from an iterable using a key selector function.
function groupBy<T, K>(
  it: Iterable<T>,
  getKey: (item: T) => K,
): Map<K, T[]>
import { groupBy } from "@temelj/iterator";

const items = [
  { category: "fruit", name: "apple" },
  { category: "fruit", name: "banana" },
  { category: "vegetable", name: "carrot" },
];

const grouped = groupBy(items, (item) => item.category);
// Map {
//   "fruit" => [{ category: "fruit", name: "apple" }, { category: "fruit", name: "banana" }],
//   "vegetable" => [{ category: "vegetable", name: "carrot" }]
// }

chunk

Splits an iterable into arrays of a specific size.
function chunk<T>(iterable: Iterable<T>, size: number): T[][]
import { chunk } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5, 6, 7];
const chunks = chunk(numbers, 3);
// Result: [[1, 2, 3], [4, 5, 6], [7]]

window

Yields a sliding window over the iterable.
function window<T>(iterable: Iterable<T>, size: number): T[][]
import { window } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5];
const windows = window(numbers, 3);
// Result: [[1, 2, 3], [2, 3, 4], [3, 4, 5]]

zip

Combines two iterables into tuples until one is exhausted.
function zip<T, U>(a: Iterable<T>, b: Iterable<U>): [T, U][]
import { zip } from "@temelj/iterator";

const names = ["Alice", "Bob", "Charlie"];
const ages = [25, 30, 35];
const zipped = zip(names, ages);
// Result: [["Alice", 25], ["Bob", 30], ["Charlie", 35]]

flatten

Flattens nested iterables by one level.
function flatten<T>(iterable: Iterable<Iterable<T> | T>): T[]
import { flatten } from "@temelj/iterator";

const nested = [[1, 2], [3, 4], 5, [6]];
const flat = flatten(nested);
// Result: [1, 2, 3, 4, 5, 6]

unique

Returns a sequence of unique items from an iterable.
function unique<T>(
  iterable: Iterable<T>,
  identity?: (item: T) => unknown,
): T[]
import { unique } from "@temelj/iterator";

const numbers = [1, 2, 2, 3, 3, 3, 4];
const uniqueNumbers = unique(numbers);
// Result: [1, 2, 3, 4]

Set operations

union

Combines two iterables into a set of unique items from both.
function union<T>(a: Iterable<T>, b: Iterable<T>): T[]
import { union } from "@temelj/iterator";

const a = [1, 2, 3];
const b = [3, 4, 5];
const result = union(a, b);
// Result: [1, 2, 3, 4, 5]

intersection

Returns items present in both iterables.
function intersection<T>(a: Iterable<T>, b: Iterable<T>): T[]
import { intersection } from "@temelj/iterator";

const a = [1, 2, 3, 4];
const b = [3, 4, 5, 6];
const result = intersection(a, b);
// Result: [3, 4]

difference

Returns items in the first iterable that are not in the second.
function difference<T>(a: Iterable<T>, b: Iterable<T>): T[]
import { difference } from "@temelj/iterator";

const a = [1, 2, 3, 4];
const b = [3, 4, 5, 6];
const result = difference(a, b);
// Result: [1, 2]

Filtering and mapping

filterMap

Filters and maps an iterable in a single pass.
function filterMap<T, U>(
  it: Iterable<T>,
  filter: (e: T, i: number) => U | undefined,
): U[]
import { filterMap } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5];
const result = filterMap(numbers, (n) => {
  if (n % 2 === 0) {
    return n * 2; // Map even numbers
  }
  return undefined; // Filter out odd numbers
});
// Result: [4, 8]

partition

Splits an iterable into two arrays based on a predicate.
function partition<T>(
  iterable: Iterable<T>,
  predicate: (item: T) => boolean,
): [T[], T[]]
import { partition } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5, 6];
const [evens, odds] = partition(numbers, (n) => n % 2 === 0);
// evens: [2, 4, 6]
// odds: [1, 3, 5]

Taking and skipping

take

Takes the first n elements from an iterable.
function take<T>(iterable: Iterable<T>, n: number): T[]
import { take } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5];
const first3 = take(numbers, 3);
// Result: [1, 2, 3]

skip

Skips the first n elements of an iterable.
function skip<T>(iterable: Iterable<T>, n: number): T[]
import { skip } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5];
const rest = skip(numbers, 2);
// Result: [3, 4, 5]

takeWhile

Takes elements while the predicate returns true.
function takeWhile<T>(
  iterable: Iterable<T>,
  predicate: (item: T) => boolean,
): T[]
import { takeWhile } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 1, 2];
const result = takeWhile(numbers, (n) => n < 4);
// Result: [1, 2, 3]

skipWhile

Skips elements while the predicate returns true.
function skipWhile<T>(
  iterable: Iterable<T>,
  predicate: (item: T) => boolean,
): T[]
import { skipWhile } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5];
const result = skipWhile(numbers, (n) => n < 3);
// Result: [3, 4, 5]

Finding and testing

find

Finds the first element matching a predicate.
function find<T>(
  iterable: Iterable<T>,
  predicate: (item: T) => boolean,
): T | undefined
import { find } from "@temelj/iterator";

const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
];

const user = find(users, (u) => u.id === 2);
// Result: { id: 2, name: "Bob" }

any

Checks if any element satisfies the predicate.
function any<T>(
  iterable: Iterable<T>,
  predicate: (item: T) => boolean,
): boolean
import { any } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5];
const hasEven = any(numbers, (n) => n % 2 === 0);
// Result: true

all

Checks if all elements satisfy the predicate.
function all<T>(
  iterable: Iterable<T>,
  predicate: (item: T) => boolean,
): boolean
import { all } from "@temelj/iterator";

const numbers = [2, 4, 6, 8];
const allEven = all(numbers, (n) => n % 2 === 0);
// Result: true

count

Counts elements, optionally matching a predicate.
function count<T>(
  iterable: Iterable<T>,
  predicate?: (item: T) => boolean,
): number
import { count } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5];
const total = count(numbers);
// Result: 5

Min/max operations

minBy

Finds the minimum element using a selector function.
function minBy<T>(
  iterable: Iterable<T>,
  selector: (item: T) => number,
): T | undefined
import { minBy } from "@temelj/iterator";

const items = [
  { name: "apple", price: 1.5 },
  { name: "banana", price: 0.8 },
  { name: "orange", price: 1.2 },
];

const cheapest = minBy(items, (item) => item.price);
// Result: { name: "banana", price: 0.8 }

maxBy

Finds the maximum element using a selector function.
function maxBy<T>(
  iterable: Iterable<T>,
  selector: (item: T) => number,
): T | undefined
import { maxBy } from "@temelj/iterator";

const items = [
  { name: "apple", price: 1.5 },
  { name: "banana", price: 0.8 },
  { name: "orange", price: 1.2 },
];

const expensive = maxBy(items, (item) => item.price);
// Result: { name: "apple", price: 1.5 }

First and last

first

Returns the first element of an iterable.
function first<T>(iterable: Iterable<T>): T | undefined
import { first } from "@temelj/iterator";

const numbers = [1, 2, 3];
const firstNum = first(numbers);
// Result: 1

last

Returns the last element of an iterable.
function last<T>(iterable: Iterable<T>): T | undefined
import { last } from "@temelj/iterator";

const numbers = [1, 2, 3];
const lastNum = last(numbers);
// Result: 3

isEmpty

Checks if an iterable is empty.
function isEmpty<T>(iterable: Iterable<T>): boolean
import { isEmpty } from "@temelj/iterator";

const empty = isEmpty([]);
// Result: true

const notEmpty = isEmpty([1, 2, 3]);
// Result: false

Numeric ranges

range

Generates a numeric range with configurable step.
function range(
  start: number,
  end: number,
  step?: number,
): Generator<number>
import { range } from "@temelj/iterator";

const numbers = Array.from(range(0, 5));
// Result: [0, 1, 2, 3, 4]

parseNumericRange

Parses a string representation of a numeric range.
function parseNumericRange(s: string): NumericRange
import { parseNumericRange, flattenNumericRange } from "@temelj/iterator";

const range = parseNumericRange("1,3..5,10");
const values = flattenNumericRange(range);
// Result: [1, 3, 4, 10]

numericRangeContains

Checks if a numeric range contains a value.
function numericRangeContains(
  range: NumericRange,
  value: number,
): boolean
import { parseNumericRange, numericRangeContains } from "@temelj/iterator";

const range = parseNumericRange("1..5,10");
const contains3 = numericRangeContains(range, 3);
// Result: true

const contains7 = numericRangeContains(range, 7);
// Result: false

Combinatorics

cartesianProduct

Generates the cartesian product of two iterables.
function cartesianProduct<T, U>(
  a: Iterable<T>,
  b: Iterable<U>,
): [T, U][]
import { cartesianProduct } from "@temelj/iterator";

const colors = ["red", "blue"];
const sizes = ["S", "M", "L"];
const combinations = cartesianProduct(colors, sizes);
// Result: [
//   ["red", "S"], ["red", "M"], ["red", "L"],
//   ["blue", "S"], ["blue", "M"], ["blue", "L"]
// ]

permutations

Generates all permutations of the input iterable.
function permutations<T>(iterable: Iterable<T>): T[][]
import { permutations } from "@temelj/iterator";

const result = permutations([1, 2, 3]);
// Result: [
//   [1, 2, 3], [1, 3, 2],
//   [2, 1, 3], [2, 3, 1],
//   [3, 1, 2], [3, 2, 1]
// ]

combinations

Generates all combinations of a specific size.
function combinations<T>(iterable: Iterable<T>, n: number): T[][]
import { combinations } from "@temelj/iterator";

const result = combinations([1, 2, 3, 4], 2);
// Result: [
//   [1, 2], [1, 3], [1, 4],
//   [2, 3], [2, 4],
//   [3, 4]
// ]

Random sampling

sample

Returns a random element from an array.
function sample<T>(array: T[]): T | undefined
import { sample } from "@temelj/iterator";

const items = ["apple", "banana", "orange"];
const randomItem = sample(items);
// Result: random item from array

sampleList

Returns a list of random samples (with replacement).
function sampleList<T>(array: T[], count: number): T[]
import { sampleList } from "@temelj/iterator";

const items = [1, 2, 3, 4, 5];
const samples = sampleList(items, 3);
// Result: [2, 5, 2] (example, allows duplicates)

sampleListUnique

Returns a list of random samples without replacement.
function sampleListUnique<T>(array: T[], count: number): T[]
import { sampleListUnique } from "@temelj/iterator";

const items = [1, 2, 3, 4, 5];
const samples = sampleListUnique(items, 3);
// Result: [2, 5, 1] (example, no duplicates)

arrayShuffle

Shuffles the elements of an array in place.
function arrayShuffle<T>(array: T[]): T[]
import { arrayShuffle } from "@temelj/iterator";

const numbers = [1, 2, 3, 4, 5];
arrayShuffle(numbers);
// Result: [3, 1, 5, 2, 4] (example, random order)

Array operations

arrayEquals

Compares two arrays for deep equality.
function arrayEquals<T>(
  a: T[],
  b: T[],
  compare?: (a: T, b: T) => boolean,
): boolean
import { arrayEquals } from "@temelj/iterator";

const equal = arrayEquals([1, 2, 3], [1, 2, 3]);
// Result: true

const notEqual = arrayEquals([1, 2, 3], [1, 2, 4]);
// Result: false

arrayBinarySearch

Performs a binary search on a sorted array.
function arrayBinarySearch<T>(
  arr: T[],
  value: T,
  compare: (a: T, b: T) => number,
): Result<number, number>
import { arrayBinarySearch } from "@temelj/iterator";
import { unwrap, isOk } from "@temelj/result";

const numbers = [1, 2, 3, 5, 8, 13];
const result = arrayBinarySearch(numbers, 5, (a, b) => a - b);

if (isOk(result)) {
  console.log(`Found at index ${unwrap(result)}`);
  // Output: "Found at index 3"
}

arrayContainsDuplicates

Checks if an array contains any duplicate elements.
function arrayContainsDuplicates<T>(
  arr: T[],
  compare?: (a: T, b: T) => boolean,
): boolean
import { arrayContainsDuplicates } from "@temelj/iterator";

const hasDuplicates = arrayContainsDuplicates([1, 2, 3, 2]);
// Result: true

const noDuplicates = arrayContainsDuplicates([1, 2, 3, 4]);
// Result: false

Tree traversal

traverseBfs

Traverses a tree structure using breadth-first search.
function traverseBfs<T>(
  root: T,
  getChildren: (node: T) => Iterable<T>,
): Generator<T>
import { traverseBfs } from "@temelj/iterator";

const tree = {
  value: 1,
  children: [
    { value: 2, children: [] },
    { value: 3, children: [{ value: 4, children: [] }] },
  ],
};

for (const node of traverseBfs(tree, (n) => n.children)) {
  console.log(node.value);
}
// Output: 1, 2, 3, 4

traverseDfs

Traverses a tree structure using depth-first search (pre-order).
function traverseDfs<T>(
  root: T,
  getChildren: (node: T) => Iterable<T>,
): Generator<T>
import { traverseDfs } from "@temelj/iterator";

const tree = {
  value: 1,
  children: [
    { value: 2, children: [] },
    { value: 3, children: [{ value: 4, children: [] }] },
  ],
};

for (const node of traverseDfs(tree, (n) => n.children)) {
  console.log(node.value);
}
// Output: 1, 2, 3, 4
The @temelj/iterator package provides lazy evaluation where possible through generator functions, making it memory-efficient for large datasets.

Build docs developers (and LLMs) love