type IterableValue = Iter extends Iterable ? V : never; type MapIterableValues[]> = { [P in keyof Iters]: IterableValue; }; type ZipValue[]> = MapIterableValues; type ZipLongestValue[]> = { [P in keyof Iters]: IterableValue | undefined; }; type ConcatValue[]> = MapIterableValues[number]; type FlatValue = T extends Iterable ? V : T; /** * A stream is an iterable, lazy sequence of elements. * * @typeParam T the type of the elements within the stream */ declare abstract class Stream implements Iterable { private constructor(); /** * Wraps an iterable into a stream. * * The returned stream can be iterated multiple times if the original iterable can also * be iterated multiple times (some iterables, like generators, do not support repeated iteration). * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * Stream.from([]); // Wraps any iterable * Stream.from(Stream.empty()); // Returns original stream for stream arguments * ``` */ static from(iterable: Iterable): Stream; static from(iterable: Iterable | null | undefined): Stream; /** * Creates a new, empty stream. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * Stream.empty().count(); // 0 * ``` */ static empty(): Stream; /** * Creates a stream from the given items. */ static of(...items: U[]): Stream; /** * Generates [index, value] tuples where value is from the original iterable * and index is the index of the current value. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * * const result = Stream.enumerate(["a", "b"]).toArray(); // [[0, "a"], [1, "b"]] * ``` */ static enumerate(iterable: Iterable): Stream<[index: number, value: U]>; /** * Generates a stream by repeatedly invoking the provided `supplier` function. * The returned stream is infinite, truncate the stream accordingly by using * for example `take()`, or break in a `for...of` loop. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * * let nextValue = 1; * function generateNumbers() { * return nextValue++; * } * * const items = Stream.generate(generateNumbers).take(4).toArray(); // [1, 2, 3, 4] * ``` */ static generate(supplier: () => U): Stream; /** * Creates a stream that iterates over the keys of the given object. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const input = { a: 1, b: 2}; * const output = Stream.keys(input).map((k) => k + k).toArray(); // ["aa", "bb"] (order might differ) * ``` */ static keys(object: Record): Stream; /** * Creates a stream that iterates over the values of the given object. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const input = { a: 1, b: 2}; * const output = Stream.values(input).map((v) => v * 2).toArray(); // [2, 4] (order might differ) * ``` */ static values(object: Record): Stream; /** * Creates a stream that iterates over the [key, value] pairs of the given object. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const input = { a: 1, b: 2}; * const output = Stream.entries(input).map((e) => `${e[0]}${e[1]}`).toArray(); // ["a1", "b2"] (order might differ) * ``` */ static entries(object: Record): Stream<[key: K, value: U]>; /** * Generates a stream of `count` integers, starting with 0. * In other words, this produces the interval `[0, 1, ..., count)`. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const numbers = Stream.integers(3).toArray(); // [0, 1, 2] * ``` * * @param count the number of integers to produce */ static integers(count: number): Stream; /** * Generates a stream of `count` integers, starting with the provided `start` index. * In other words, this produces the interval `[start +0, start +1, ..., start +count)`. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const numbers = Stream.integers(3, 4).toArray(); // [3, 4, 5, 6] * ``` * * @param start the start value * @param count the number of integers to produce */ static integers(start: number, count: number): Stream; /** * Generates an infinite stream of integers, starting with `start` (which defaults to 0). * In other words, this produces the interval `[start, start + 1, ...)`. * The returned stream is infinite, truncate the stream accordingly by using for example `take()`, * or break in a `for...of` loop. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const numbers = Stream.allIntegers().take(3).toArray(); // [0, 1, 2] * ``` * * @param start the start value */ static allIntegers(start?: number): Stream; /** * Creates a new stream by chaining the given iterables after each other. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const result = Stream.concat([1], [2]).toArray(); // [1, 2] * ``` * * @param iterables the iterables to concatenate */ static concat[] | [Iterable]>(...iterables: Ts): Stream>; /** * Creates a new stream by zipping the elements of the given iterables. The iterables will be * iterated in parallel, so each element of the new stream will be a tuple with one element per iterable. * * The stream stops when the shortest of the given iterables has ended. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const left = [1, 2]; * const right = ["a", "b", "c"]; * const zipped = Stream.zip(left, right).toArray(); // [[1, "a"], [2, "b"]] * ``` * * @param iterables the iterables to concatenate */ static zip[] | [Iterable]>(...iterables: Ts): Stream>; /** * Creates a new stream by zipping the elements of the given iterables. The iterables will be * iterated in parallel, so each element of the new stream will be a tuple with one element per iterable. * * The stream stops when the longest of the given iterables has ended. When individual iterables * are exhausted, their tuple items are set to undefined. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const left = [1, 2]; * const right = ["a", "b", "c"]; * const zipped = Stream.zipLongest(left, right).toArray(); // [[1, "a"], [2, "b"], [undefined, "c"]] * ``` * * @param iterables the iterables to zip */ static zipLongest[] | [Iterable]>(...iterables: Ts): Stream>; /** * Generates [index, value] tuples where value is from the original iterable * and index is the index of the current value. * * @see {@link Stream.enumerate} */ enumerate(): Stream<[index: number, value: T]>; /** * Returns a stream that filters the input by `predicate`. Only items for which `predicate(item)` * returns true will be produced by the stream. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [1, -2, 3]; * const result = Stream.from(items).filter(n => n > 0).toArray(); // [1, 3] * ``` * * @param predicate * A function that returns `true` if the item should be part of the returned stream. */ filter(predicate: (item: T) => item is U): Stream; filter(predicate: (item: T) => boolean): Stream; /** * Returns a stream that maps all elements of the input by using the provided `transform` function. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [1, 2]; * const result = Stream.from(items).map(n => n + 1).toArray(); // [2, 3] * ``` * * @param transform * A function that maps each item to a another item of an arbitrary type. */ map(transform: (item: T) => U): Stream; /** * Returns a stream that transforms all items using the given `transform` function and * then discards all items that are `null` or `undefined`. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const persons = [{ age: 7 }, { age: 18 }, { age: 21 }]; * const adultAges = Stream.from(persons).filterMap( * (person) => person.age >= 18 ? person.age : undefined * ).toArray(); // [18, 21] * ``` * * @param transform * A function that maps each item to a nullable item of an arbitrary type. * Return values `null` and `undefined` will not be included in the returned stream. */ filterMap(transform: (item: T) => U | null | undefined): Stream>; /** * Returns a stream that flattens its input by one layer (elements that are iterable become * multiple elements of the new stream). * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [[1], [2, 3]]; * const result = Stream.from(items).flat().toArray(); // [1, 2, 3] * ``` */ flat(): Stream>; /** * Returns a stream that skips the first `count` elements of its input. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [1, 2, 3]; * const result = Stream.from(items).skip(1).toArray(); // [2, 3] * ``` * * @param count the number of items to skip */ skip(count: number): Stream; /** * Returns a stream that skips elements while the predicate returns `true`. * Once the predicate returns `false`, all the following items will be included * in the returned stream. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [1, 2, 3, 4, -1, -2, -3]; * const result = Stream.from(items).skipWhile((n) => n < 4).toArray(); // [4, -1, -2, -3] * ``` * * @param predicate * A predicate determining if items shall be skipped. Once the predicate * returns `false`, all remaining items are included in the returned stream. */ skipWhile(predicate: (item: T) => boolean): Stream; /** * Returns a stream that limits the input to at most `count` elements. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [1, 2, 3]; * const result = Stream.from(items).take(1).toArray(); // [1] * ``` * * @param count the number of elements to include in the returned stream */ take(count: number): Stream; /** * Returns a stream over the input that produces values while the predicate * returns true. The stream will be cut off when the predicate returns `false` * for the first time. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [1, 2, 3, 4, -1, -2, -3]; * const result = Stream.from(items).takeWhile((n) => n < 4).toArray(); // [1, 2, 3] * ``` * * @param predicate * Determines when including items in the returned stream shall be stopped. */ takeWhile(predicate: (item: T) => boolean): Stream; /** * Returns a stream that repeats its contents `count` times. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = ["a", "b"]; * const repeated = Stream.from(items).repeat(2).toArray(); // ["a", "b", "a", "b"]; * ``` * * @param count the number of repetitions */ repeat(count: number): Stream; /** * Returns a stream that repeats the elements of this stream. The returned stream is * infinite, truncate the stream accordingly by using for example `take()`, or break * in a `for...of` loop. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [1, 2]; * const cycled = Stream.from(items).cycle().take(5).toArray(); // [1, 2, 1, 2, 1] * ``` */ cycle(): Stream; /** * Returns a stream over the original items grouped into chunks of size `chunkSize`. * Up to `chunkSize` consecutive elements will be gathered into an array and then * returned by the stream. * * All arrays, except for the last one, will be of length `chunkSize`. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const items = [1, 2, 3, 4, 5]; * const chunked = Stream.from(items).chunk(3).toArray(); // [[1, 2, 3], [4, 5]] * ``` * * @param chunkSize the maximum chunk size */ chunk(chunkSize: number): Stream; /** * Chains the given iterables after `this` (see static `concat` function for details). * * @param iterables the iterables to concatenate */ concatWith[] | [Iterable]>(...iterables: Ts): Stream>; /** * Zips the given iterables with `this` (see static `zip` function for details). * The length of the resulting stream is the *minimum* length of all iterables. * * @param iterables a series of iterables who's items will be _zipped_ next to the items of `this`. */ zipWith[] | [Iterable]>(...iterables: Ts): Stream>; /** * Zips the given iterables with `this` with the zipLongest algorithm (see static * `zipLongest` function for details). * The length of the resulting stream is the *maximum* length of all iterables, with empty * positions filled with `undefined`. * * @param iterables a series of iterables who's items will be _zipped_ next to the items of `this`. */ zipLongestWith[] | [Iterable]>(...iterables: Ts): Stream, ...Ts]>>; /** * Groups items together for which `keyFunc` returns the same value. * The `keyFunc` function should generate keys that are supported by * JavaScript's `Map` type. * * NOTE: This function reads the entire stream into memory and stores * items in an internal map, which may be inefficient for very large datasets. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const persons = [ * { name: "A", age: 18 }, * { name: "B", age: 18 }, * { name: "C", age: 20 }, * ]; * const byAge = Stream.from(persons) * .groupBy((p) => p.age) * .toObject(); // { 18: [person A, person B], 20: [person C] } * ``` * * @param keyFunc * Given an item from the stream, returns a group key for that item. * All items with an equal group key end up in the same group. */ groupBy(keyFunc: (item: T) => U): Stream<[U, T[]]>; /** * Returns a stream that groups adjacent elements for which the predicate returns `true` into arrays. * * This is different from `groupBy` because it allows arbitrary conditions for grouping. * However, only elements next to each other can belong to a group. * A new group is started whenever an element is encountered that does not belong to the current group. * * @example * ```ts * const numbers = [1, 2, 4, 3, 0]; * const grouped = Stream.from(numbers) * .groupAdjacent((l, r) => Math.abs(l - r) <= 1) // close items belong to the same group * .toArray(); // [[1, 2], [4, 3], [0]] * ``` * * @param predicate * A function that returns true if `left` and `right` belong to the same group. */ groupAdjacent(predicate: (left: T, right: T) => boolean): Stream; /** * Returns a stream that has all its elements sorted according to the given `compareFunc`. * The comparison function is optional, the Array sort behavior will be used by default when * the function is omitted. The function must behave as expected by the `Array.sort()` method. * * See also: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) * * NOTE: This function reads the entire stream into memory and stores all elements in an array * to be able to sort it. This may be inefficient for very large datasets. * * @param compareFunc * Given two elements `left` and `right`, returns `< 0` if `left < right`, `> 0` if `right > left` * and `0` otherwise. * When not specified, elements are compared using standard `<` and `>` (which might be useless, * e.g. when keys are objects or arrays). */ sort(compareFunc?: (left: T, right: T) => number): Stream; /** * Like `sort()`, but sorts by comparing keys derived from the stream's items. * * NOTE: This function reads the entire stream into memory and stores all elements in an array * to be able to sort it. This may be inefficient for very large datasets. * * @example * ```ts * const items = [ * { name: "A", age: 18 }, * { name: "B", age: 28 }, * { name: "C", age: 17 } * ]; * const sorted = Stream.from(items).sortBy(item => item.age).toArray(); * ``` * * @param keyFunc * Given an item, returns a sort key for comparison during sorting. * This function should be fast, because it will be invoked at least once for every element. * * @param compareFunc * Given two keys derived by `keyFunc`, returns `< 0` if `left < right`, `> 0` if `right > left` and `0` otherwise. * When not specified, keys are compared using standard `<` and `>` (which might be useless, * e.g. when keys are objects or arrays). * * @returns * A new stream of sorted elements. */ sortBy(keyFunc: (item: T) => U, compareFunc?: (leftKey: U, rightKey: U) => number): Stream; /** * Returns a stream that consists of all elements of this stream, with duplicates removed. * The relative order of the remaining elements is preserved. * * NOTE: This function reads the entire stream into memory and stores all elements in a Set * for de-duplication. This may be inefficient for very large datasets. * * @example * ```ts * const items = [ * {age: 1}, * {age: 2}, * {age: 3}, * {age: 1}, * {age: 3}, * {age: 3} * ]; * const result = Stream.from(items).map(i => i.age).unique().toArray(); * // result == [1, 2, 3] * ``` * * @returns * A new stream with unique items. */ unique(): Stream; /** * Returns a stream that consists of all elements of this stream, in reversed order. * * NOTE: This function reads the entire stream into memory in order to reverse the item order. * This may be inefficient for very large datasets. * * @example * ```ts * const items = Stream.integers(4).reverse().toArray(); // [3, 2, 1, 0] * ``` */ reverse(): Stream; /** * Returns the first item in this stream, or undefined if the stream is empty. */ first(): T | undefined; /** * Returns the last item in this stream, or undefined if this stream is empty. * * NOTE: This iterates over the entire stream in order to find the last element. * Be aware of the performance implications: the function should not be called repeatedly * (cache the result instead) and you should ensure that your stream is finite. */ last(): T | undefined; /** * Determines if the given condition matches to at least one of the stream's items. * * @param predicate * Returns `true` if any item in the stream fulfills the given predicate, `false` otherwise. */ some(predicate: (item: T) => boolean): boolean; /** * Determines if all items in the stream fulfill the given predicate. * * NOTE: Trivially returns `true` if the stream is empty. * * @param predicate * Returns `true` if all item in the stream fulfills the given predicate, `false` otherwise. */ every(predicate: (item: T) => boolean): boolean; /** * Returns `true` if this stream contains an element that compares equal * to `item`. Comparisons use strict equality (`===`). */ includes(item: T): boolean; /** * Searches the elements in this stream for an item for which the `predicate` * returns `true`. Returns the item on success or `undefined` if no item was found. */ find(predicate: (item: T) => item is U): U; find(predicate: (item: T) => boolean): T | undefined; /** * Invokes the callback for every item in the stream. * Works exactly like Array's `forEach` function, with the exception that no source array is passed. */ forEach(callback: (item: T, index: number) => void): void; /** * Invokes the `reduceFunc` for every element of the stream in order to provide a single return value. * Works exactly like Array's `reduce` function, with the exception that no source array is passed. */ reduce(reduceFunc: (currentValue: T, item: T, index: number) => T): T; reduce(reduceFunc: (currentValue: U, item: T, index: number) => U, initial: U): U; /** * Joins all elements of this stream together into a string. * Individual elements will be converted to string (via `String(elements)`) * and separated by `separator`. * * @param separator The separator to use between two elements. Defaults to `","`. */ join(separator?: string): string; /** * Returns the number of elements in this stream. * * NOTE: this will iterate over the entire stream! */ count(): number; /** * Returns `true` if there is at least one element in this stream, `false` otherwise. */ isEmpty(): boolean; /** * Returns the largest stream item according to the given `compareFunc`. * If multiple candidates for the largest element compare equal to each other, * the first of those items (according to the stream order) will be returned. * * @param compareFunc * Given two items `left` and `right`, returns `< 0` if `left < right`, `> 0` if `left > right` * and `0` otherwise. * When not specified, items are compared using standard `<` and `>` (which might be useless, * e.g. when items are objects or arrays). * * @returns the largest item or `undefined` if the stream is empty. */ max(compareFunc?: (left: T, right: T) => number): T | undefined; /** * Like {@link max}, but returns the smallest item instead. */ min(compareFunc?: (left: T, right: T) => number): T | undefined; /** * Like `max()`, but compares keys derived from the stream's items instead of the items themselves. * The item with the largest key will be returned (or undefined if the stream is empty). * * @param keyFunc * Given an item, returns a sort key for comparison during sorting. * This function should be fast, because it will be invoked at least once for every element. * * @param compareFunc * Given two keys derived by `keyFunc`, returns `< 0` if `left < right`, `> 0` if `left > right` and `0` otherwise. * When not specified, keys are compared using standard `<` and `>` (which might be useless, * e.g. when keys are objects or arrays). * * @returns the largest item or `undefined` if the stream is empty. */ maxBy(keyFunc: (value: T) => U, compareFunc?: (left: U, right: U) => number): T | undefined; /** * Like {@link maxBy}, but returns the item with the smallest key instead. */ minBy(keyFunc: (value: T) => U, compareFunc?: (left: U, right: U) => number): T | undefined; /** * Gathers all elements of this stream into an array. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const array = Stream.integers(3).toArray(); // [0, 1, 2] * ``` */ toArray(): T[]; /** * Gathers all elements of this stream into an object. * The elements must be [key, value] pairs, and the keys must be * strings, symbols or numbers. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const object = Stream.from(["a", "b", "c"]) * .map((v) => [v, v + "!"]) * .toObject(); // { a: "a!", b: "b!", c: "c!"} * ``` */ toObject(this: T extends [PropertyKey, any] ? this : never): T extends [infer K, infer V] ? [K] extends [PropertyKey] ? Record : never : never; /** * Gathers all elements of this stream into a set. * * Note: elements are inserted into the set in the order they occur in the stream. * Iterating over the set will yield the same order because sets maintain their insertion order. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const set = Stream.integers(3).toSet(); // set of 0, 1, 2 * ``` */ toSet(): Set; /** * Gathers the elements of this stream into a map. * The elements must be [key, value] pairs. * * Note: elements are inserted into the map in the order they occur in the stream. * Iterating over the map will yield the same order because maps maintain their insertion order. * * @example * ```ts * import { Stream } from "apprt-streams/Stream"; * const map = Stream.from(["a", "b", "c"]) * .map((v) => [v, v + "!"]) * .toMap(); // // a -> a!, b -> b!, c -> c! * ``` */ toMap(this: T extends [any, any] ? this : never): T extends [infer K, infer V] ? Map : never; /** * Allows iteration in for...of loops. * * @example * * ```ts * for (const value of Stream.integers(5)) { * console.info(value); * } * ``` */ abstract [Symbol.iterator](): Iterator; } export { Stream };