| /** | |
| * Works with JavaScript values that implement `[Symbol.iterator]`. | |
| * | |
| * Iterables include arrays, strings, generators, sets, and custom lazy | |
| * sequences. The helpers in this module let code transform, search, group, and | |
| * fold iterable values while preserving the input as an iterable instead of | |
| * forcing an array first. | |
| * | |
| * @since 2.0.0 | |
| */ | |
| import type { NonEmptyArray } from "./Array.ts" | |
| import * as Equal from "./Equal.ts" | |
| import { dual } from "./Function.ts" | |
| import type { Option } from "./Option.ts" | |
| import * as O from "./Option.ts" | |
| import { isBoolean } from "./Predicate.ts" | |
| import type * as Record from "./Record.ts" | |
| import type { Result } from "./Result.ts" | |
| import * as R from "./Result.ts" | |
| import * as Tuple from "./Tuple.ts" | |
| import type { NoInfer } from "./Types.ts" | |
| /** | |
| * Creates an iterable by applying a function to consecutive integers. | |
| * | |
| * **Details** | |
| * | |
| * The function is called with each index starting from `0`. If no length is | |
| * specified, the iterable is infinite. This is useful for generating | |
| * sequences, patterns, or any indexed data. | |
| * | |
| * **Example** (Generating values by index) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Generate first 5 even numbers | |
| * const evens = Iterable.makeBy((n) => n * 2, { length: 5 }) | |
| * console.log(Array.from(evens)) // [0, 2, 4, 6, 8] | |
| * | |
| * // Generate squares | |
| * const squares = Iterable.makeBy((n) => n * n, { length: 4 }) | |
| * console.log(Array.from(squares)) // [0, 1, 4, 9] | |
| * | |
| * // Infinite sequence (be careful when consuming!) | |
| * const naturals = Iterable.makeBy((n) => n) | |
| * const first10 = Iterable.take(naturals, 10) | |
| * console.log(Array.from(first10)) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| export const makeBy = <A>(f: (i: number) => A, options?: { | |
| readonly length?: number | |
| }): Iterable<A> => { | |
| const max = options?.length !== undefined ? Math.max(1, Math.floor(options.length)) : Infinity | |
| return { | |
| [Symbol.iterator]() { | |
| let i = 0 | |
| return { | |
| next(): IteratorResult<A> { | |
| if (i < max) { | |
| return { value: f(i++), done: false } | |
| } | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * Returns an iterable of integers starting at `start` and increasing by `1`. | |
| * | |
| * **Details** | |
| * | |
| * When `end` is provided and `start <= end`, both endpoints are included. When | |
| * `end` is omitted, the iterable is unbounded. When `start > end`, the | |
| * iterable contains only `start`. | |
| * | |
| * **Example** (Creating a range) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual(Array.from(Iterable.range(1, 3)), [1, 2, 3]) | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| export const range = (start: number, end?: number): Iterable<number> => { | |
| if (end === undefined) { | |
| return makeBy((i) => start + i) | |
| } | |
| return makeBy((i) => start + i, { | |
| length: start <= end ? end - start + 1 : 1 | |
| }) | |
| } | |
| /** | |
| * Returns a `Iterable` containing a value repeated the specified number of times. | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to an integer greater than or equal to `1`. | |
| * | |
| * **Example** (Repeating a value) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual(Array.from(Iterable.replicate("a", 3)), ["a", "a", "a"]) | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| export const replicate: { | |
| /** | |
| * Returns a `Iterable` containing a value repeated the specified number of times. | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to an integer greater than or equal to `1`. | |
| * | |
| * **Example** (Repeating a value) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual(Array.from(Iterable.replicate("a", 3)), ["a", "a", "a"]) | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| (n: number): <A>(a: A) => Iterable<A> | |
| /** | |
| * Returns a `Iterable` containing a value repeated the specified number of times. | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to an integer greater than or equal to `1`. | |
| * | |
| * **Example** (Repeating a value) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual(Array.from(Iterable.replicate("a", 3)), ["a", "a", "a"]) | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| <A>(a: A, n: number): Iterable<A> | |
| } = dual(2, <A>(a: A, n: number): Iterable<A> => makeBy(() => a, { length: n })) | |
| /** | |
| * Repeats an iterable `n` times, yielding the full contents of `self` for each | |
| * repetition. | |
| * | |
| * **When to use** | |
| * | |
| * Use to repeat an iterable's contents a specific number of times. | |
| * | |
| * **Details** | |
| * | |
| * The result is lazy. Each repetition obtains a new iterator from `self`. | |
| * | |
| * @see {@link forever} for repeating without an upper bound | |
| * @see {@link replicate} for repeating a single value | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const repeat: { | |
| /** | |
| * Repeats an iterable `n` times, yielding the full contents of `self` for each | |
| * repetition. | |
| * | |
| * **When to use** | |
| * | |
| * Use to repeat an iterable's contents a specific number of times. | |
| * | |
| * **Details** | |
| * | |
| * The result is lazy. Each repetition obtains a new iterator from `self`. | |
| * | |
| * @see {@link forever} for repeating without an upper bound | |
| * @see {@link replicate} for repeating a single value | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| (n: number): <A>(self: Iterable<A>) => Iterable<A> | |
| /** | |
| * Repeats an iterable `n` times, yielding the full contents of `self` for each | |
| * repetition. | |
| * | |
| * **When to use** | |
| * | |
| * Use to repeat an iterable's contents a specific number of times. | |
| * | |
| * **Details** | |
| * | |
| * The result is lazy. Each repetition obtains a new iterator from `self`. | |
| * | |
| * @see {@link forever} for repeating without an upper bound | |
| * @see {@link replicate} for repeating a single value | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| <A>(self: Iterable<A>, n: number): Iterable<A> | |
| } = dual(2, <A>(self: Iterable<A>, n: number): Iterable<A> => flatten(makeBy(() => self, { length: n }))) | |
| /** | |
| * Repeats an iterable without an upper bound. | |
| * | |
| * **When to use** | |
| * | |
| * Use to cycle a reusable iterable without an upper bound when a downstream | |
| * consumer controls how many values are taken. | |
| * | |
| * **Gotchas** | |
| * | |
| * The returned iterable is lazy and should usually be bounded with `take` or | |
| * another terminating consumer before materializing it. | |
| * | |
| * @see {@link repeat} for repeating an iterable a specific number of times | |
| * @see {@link take} for bounding the unbounded result before materializing it | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const forever = <A>(self: Iterable<A>): Iterable<A> => repeat(self, Infinity) | |
| /** | |
| * Takes a record and returns an Iterable of tuples containing its keys and values. | |
| * | |
| * **Example** (Converting a record to entries) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * const x = { a: 1, b: 2, c: 3 } | |
| * assert.deepStrictEqual(Array.from(Iterable.fromRecord(x)), [["a", 1], ["b", 2], [ | |
| * "c", | |
| * 3 | |
| * ]]) | |
| * ``` | |
| * | |
| * @category converting | |
| * @since 2.0.0 | |
| */ | |
| export const fromRecord = <K extends string, A>(self: Readonly<Record<K, A>>): Iterable<[K, A]> => ({ | |
| *[Symbol.iterator]() { | |
| for (const key in self) { | |
| if (Object.hasOwn(self, key)) { | |
| yield [key, self[key]] | |
| } | |
| } | |
| } | |
| }) | |
| /** | |
| * Prepends an element to the front of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **Example** (Prepending an element) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [2, 3, 4] | |
| * const withOne = Iterable.prepend(numbers, 1) | |
| * console.log(Array.from(withOne)) // [1, 2, 3, 4] | |
| * | |
| * // Works with any iterable | |
| * const letters = "abc" | |
| * const withZ = Iterable.prepend(letters, "z") | |
| * console.log(Array.from(withZ)) // ["z", "a", "b", "c"] | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| export const prepend: { | |
| /** | |
| * Prepends an element to the front of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **Example** (Prepending an element) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [2, 3, 4] | |
| * const withOne = Iterable.prepend(numbers, 1) | |
| * console.log(Array.from(withOne)) // [1, 2, 3, 4] | |
| * | |
| * // Works with any iterable | |
| * const letters = "abc" | |
| * const withZ = Iterable.prepend(letters, "z") | |
| * console.log(Array.from(withZ)) // ["z", "a", "b", "c"] | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <B>(head: B): <A>(self: Iterable<A>) => Iterable<A | B> | |
| /** | |
| * Prepends an element to the front of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **Example** (Prepending an element) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [2, 3, 4] | |
| * const withOne = Iterable.prepend(numbers, 1) | |
| * console.log(Array.from(withOne)) // [1, 2, 3, 4] | |
| * | |
| * // Works with any iterable | |
| * const letters = "abc" | |
| * const withZ = Iterable.prepend(letters, "z") | |
| * console.log(Array.from(withZ)) // ["z", "a", "b", "c"] | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, head: B): Iterable<A | B> | |
| } = dual(2, <A, B>(self: Iterable<A>, head: B): Iterable<A | B> => prependAll(self, [head])) | |
| /** | |
| * Prepends the specified prefix iterable to the beginning of the specified iterable. | |
| * | |
| * **Example** (Prepending another iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual( | |
| * Array.from(Iterable.prependAll([1, 2], ["a", "b"])), | |
| * ["a", "b", 1, 2] | |
| * ) | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| export const prependAll: { | |
| /** | |
| * Prepends the specified prefix iterable to the beginning of the specified iterable. | |
| * | |
| * **Example** (Prepending another iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual( | |
| * Array.from(Iterable.prependAll([1, 2], ["a", "b"])), | |
| * ["a", "b", 1, 2] | |
| * ) | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <B>(that: Iterable<B>): <A>(self: Iterable<A>) => Iterable<A | B> | |
| /** | |
| * Prepends the specified prefix iterable to the beginning of the specified iterable. | |
| * | |
| * **Example** (Prepending another iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual( | |
| * Array.from(Iterable.prependAll([1, 2], ["a", "b"])), | |
| * ["a", "b", 1, 2] | |
| * ) | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<A | B> | |
| } = dual( | |
| 2, | |
| <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<A | B> => appendAll(that, self) | |
| ) | |
| /** | |
| * Appends an element to the end of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **When to use** | |
| * | |
| * Use to add one element after all elements of an iterable while keeping the | |
| * result as a lazy `Iterable`. | |
| * | |
| * **Details** | |
| * | |
| * The result yields every element from `self` first, then yields `last` after | |
| * `self` is exhausted. | |
| * | |
| * **Gotchas** | |
| * | |
| * If `self` is infinite or never completes, the appended element is never | |
| * reached. | |
| * | |
| * **Example** (Appending an element) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3] | |
| * const withFour = Iterable.append(numbers, 4) | |
| * console.log(Array.from(withFour)) // [1, 2, 3, 4] | |
| * | |
| * // Chain multiple appends | |
| * const result = Iterable.append( | |
| * Iterable.append([1, 2], 3), | |
| * 4 | |
| * ) | |
| * console.log(Array.from(result)) // [1, 2, 3, 4] | |
| * ``` | |
| * | |
| * @see {@link prepend} for adding one element before the existing elements | |
| * @see {@link appendAll} for appending all elements from another iterable | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| export const append: { | |
| /** | |
| * Appends an element to the end of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **When to use** | |
| * | |
| * Use to add one element after all elements of an iterable while keeping the | |
| * result as a lazy `Iterable`. | |
| * | |
| * **Details** | |
| * | |
| * The result yields every element from `self` first, then yields `last` after | |
| * `self` is exhausted. | |
| * | |
| * **Gotchas** | |
| * | |
| * If `self` is infinite or never completes, the appended element is never | |
| * reached. | |
| * | |
| * **Example** (Appending an element) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3] | |
| * const withFour = Iterable.append(numbers, 4) | |
| * console.log(Array.from(withFour)) // [1, 2, 3, 4] | |
| * | |
| * // Chain multiple appends | |
| * const result = Iterable.append( | |
| * Iterable.append([1, 2], 3), | |
| * 4 | |
| * ) | |
| * console.log(Array.from(result)) // [1, 2, 3, 4] | |
| * ``` | |
| * | |
| * @see {@link prepend} for adding one element before the existing elements | |
| * @see {@link appendAll} for appending all elements from another iterable | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <B>(last: B): <A>(self: Iterable<A>) => Iterable<A | B> | |
| /** | |
| * Appends an element to the end of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **When to use** | |
| * | |
| * Use to add one element after all elements of an iterable while keeping the | |
| * result as a lazy `Iterable`. | |
| * | |
| * **Details** | |
| * | |
| * The result yields every element from `self` first, then yields `last` after | |
| * `self` is exhausted. | |
| * | |
| * **Gotchas** | |
| * | |
| * If `self` is infinite or never completes, the appended element is never | |
| * reached. | |
| * | |
| * **Example** (Appending an element) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3] | |
| * const withFour = Iterable.append(numbers, 4) | |
| * console.log(Array.from(withFour)) // [1, 2, 3, 4] | |
| * | |
| * // Chain multiple appends | |
| * const result = Iterable.append( | |
| * Iterable.append([1, 2], 3), | |
| * 4 | |
| * ) | |
| * console.log(Array.from(result)) // [1, 2, 3, 4] | |
| * ``` | |
| * | |
| * @see {@link prepend} for adding one element before the existing elements | |
| * @see {@link appendAll} for appending all elements from another iterable | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, last: B): Iterable<A | B> | |
| } = dual(2, <A, B>(self: Iterable<A>, last: B): Iterable<A | B> => appendAll(self, [last])) | |
| /** | |
| * Concatenates two iterables, combining their elements. | |
| * | |
| * **When to use** | |
| * | |
| * Use to lazily concatenate two iterables while preserving order, yielding all | |
| * elements from `self` before `that`. | |
| * | |
| * **Details** | |
| * | |
| * The result is lazy. The iterator for `that` is not created or read until | |
| * `self` is exhausted. | |
| * | |
| * **Gotchas** | |
| * | |
| * If `self` is infinite or never completes, `that` is never reached. | |
| * | |
| * **Example** (Concatenating iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const first = [1, 2, 3] | |
| * const second = [4, 5, 6] | |
| * const combined = Iterable.appendAll(first, second) | |
| * console.log(Array.from(combined)) // [1, 2, 3, 4, 5, 6] | |
| * | |
| * // Works with different iterable types | |
| * const numbers = [1, 2] | |
| * const letters = "abc" | |
| * const mixed = Iterable.appendAll(numbers, letters) | |
| * console.log(Array.from(mixed)) // [1, 2, "a", "b", "c"] | |
| * | |
| * // Lazy evaluation - only consumes what's needed | |
| * const infinite = Iterable.range(1) | |
| * const finite = [0, -1, -2] | |
| * const result = Iterable.take(Iterable.appendAll(finite, infinite), 5) | |
| * console.log(Array.from(result)) // [0, -1, -2, 1, 2] | |
| * ``` | |
| * | |
| * @see {@link append} for appending one value instead of another iterable | |
| * @see {@link prependAll} for yielding another iterable before `self` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| export const appendAll: { | |
| /** | |
| * Concatenates two iterables, combining their elements. | |
| * | |
| * **When to use** | |
| * | |
| * Use to lazily concatenate two iterables while preserving order, yielding all | |
| * elements from `self` before `that`. | |
| * | |
| * **Details** | |
| * | |
| * The result is lazy. The iterator for `that` is not created or read until | |
| * `self` is exhausted. | |
| * | |
| * **Gotchas** | |
| * | |
| * If `self` is infinite or never completes, `that` is never reached. | |
| * | |
| * **Example** (Concatenating iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const first = [1, 2, 3] | |
| * const second = [4, 5, 6] | |
| * const combined = Iterable.appendAll(first, second) | |
| * console.log(Array.from(combined)) // [1, 2, 3, 4, 5, 6] | |
| * | |
| * // Works with different iterable types | |
| * const numbers = [1, 2] | |
| * const letters = "abc" | |
| * const mixed = Iterable.appendAll(numbers, letters) | |
| * console.log(Array.from(mixed)) // [1, 2, "a", "b", "c"] | |
| * | |
| * // Lazy evaluation - only consumes what's needed | |
| * const infinite = Iterable.range(1) | |
| * const finite = [0, -1, -2] | |
| * const result = Iterable.take(Iterable.appendAll(finite, infinite), 5) | |
| * console.log(Array.from(result)) // [0, -1, -2, 1, 2] | |
| * ``` | |
| * | |
| * @see {@link append} for appending one value instead of another iterable | |
| * @see {@link prependAll} for yielding another iterable before `self` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <B>(that: Iterable<B>): <A>(self: Iterable<A>) => Iterable<A | B> | |
| /** | |
| * Concatenates two iterables, combining their elements. | |
| * | |
| * **When to use** | |
| * | |
| * Use to lazily concatenate two iterables while preserving order, yielding all | |
| * elements from `self` before `that`. | |
| * | |
| * **Details** | |
| * | |
| * The result is lazy. The iterator for `that` is not created or read until | |
| * `self` is exhausted. | |
| * | |
| * **Gotchas** | |
| * | |
| * If `self` is infinite or never completes, `that` is never reached. | |
| * | |
| * **Example** (Concatenating iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const first = [1, 2, 3] | |
| * const second = [4, 5, 6] | |
| * const combined = Iterable.appendAll(first, second) | |
| * console.log(Array.from(combined)) // [1, 2, 3, 4, 5, 6] | |
| * | |
| * // Works with different iterable types | |
| * const numbers = [1, 2] | |
| * const letters = "abc" | |
| * const mixed = Iterable.appendAll(numbers, letters) | |
| * console.log(Array.from(mixed)) // [1, 2, "a", "b", "c"] | |
| * | |
| * // Lazy evaluation - only consumes what's needed | |
| * const infinite = Iterable.range(1) | |
| * const finite = [0, -1, -2] | |
| * const result = Iterable.take(Iterable.appendAll(finite, infinite), 5) | |
| * console.log(Array.from(result)) // [0, -1, -2, 1, 2] | |
| * ``` | |
| * | |
| * @see {@link append} for appending one value instead of another iterable | |
| * @see {@link prependAll} for yielding another iterable before `self` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<A | B> | |
| } = dual( | |
| 2, | |
| <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<A | B> => ({ | |
| [Symbol.iterator]() { | |
| const iterA = self[Symbol.iterator]() | |
| let doneA = false | |
| let iterB: Iterator<B> | |
| return { | |
| next() { | |
| if (!doneA) { | |
| const r = iterA.next() | |
| if (r.done) { | |
| doneA = true | |
| iterB = that[Symbol.iterator]() | |
| return iterB.next() | |
| } | |
| return r | |
| } | |
| return iterB.next() | |
| } | |
| } | |
| } | |
| }) | |
| ) | |
| /** | |
| * Reduces an `Iterable` from the left, keeping all intermediate results instead of only the final result. | |
| * | |
| * **Example** (Tracking running results) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Running sum of numbers | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const runningSum = Iterable.scan(numbers, 0, (acc, n) => acc + n) | |
| * console.log(Array.from(runningSum)) // [0, 1, 3, 6, 10, 15] | |
| * | |
| * // Build strings progressively | |
| * const letters = ["a", "b", "c"] | |
| * const progressive = Iterable.scan(letters, "", (acc, letter) => acc + letter) | |
| * console.log(Array.from(progressive)) // ["", "a", "ab", "abc"] | |
| * | |
| * // Track maximum values seen so far | |
| * const values = [3, 1, 4, 1, 5, 9, 2] | |
| * const runningMax = Iterable.scan(values, -Infinity, Math.max) | |
| * console.log(Array.from(runningMax)) // [-Infinity, 3, 3, 4, 4, 5, 9, 9] | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 2.0.0 | |
| */ | |
| export const scan: { | |
| /** | |
| * Reduces an `Iterable` from the left, keeping all intermediate results instead of only the final result. | |
| * | |
| * **Example** (Tracking running results) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Running sum of numbers | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const runningSum = Iterable.scan(numbers, 0, (acc, n) => acc + n) | |
| * console.log(Array.from(runningSum)) // [0, 1, 3, 6, 10, 15] | |
| * | |
| * // Build strings progressively | |
| * const letters = ["a", "b", "c"] | |
| * const progressive = Iterable.scan(letters, "", (acc, letter) => acc + letter) | |
| * console.log(Array.from(progressive)) // ["", "a", "ab", "abc"] | |
| * | |
| * // Track maximum values seen so far | |
| * const values = [3, 1, 4, 1, 5, 9, 2] | |
| * const runningMax = Iterable.scan(values, -Infinity, Math.max) | |
| * console.log(Array.from(runningMax)) // [-Infinity, 3, 3, 4, 4, 5, 9, 9] | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 2.0.0 | |
| */ | |
| <B, A>(b: B, f: (b: B, a: A) => B): (self: Iterable<A>) => Iterable<B> | |
| /** | |
| * Reduces an `Iterable` from the left, keeping all intermediate results instead of only the final result. | |
| * | |
| * **Example** (Tracking running results) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Running sum of numbers | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const runningSum = Iterable.scan(numbers, 0, (acc, n) => acc + n) | |
| * console.log(Array.from(runningSum)) // [0, 1, 3, 6, 10, 15] | |
| * | |
| * // Build strings progressively | |
| * const letters = ["a", "b", "c"] | |
| * const progressive = Iterable.scan(letters, "", (acc, letter) => acc + letter) | |
| * console.log(Array.from(progressive)) // ["", "a", "ab", "abc"] | |
| * | |
| * // Track maximum values seen so far | |
| * const values = [3, 1, 4, 1, 5, 9, 2] | |
| * const runningMax = Iterable.scan(values, -Infinity, Math.max) | |
| * console.log(Array.from(runningMax)) // [-Infinity, 3, 3, 4, 4, 5, 9, 9] | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): Iterable<B> | |
| } = dual(3, <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): Iterable<B> => ({ | |
| [Symbol.iterator]() { | |
| let acc = b | |
| let iterator: Iterator<A> | undefined | |
| function next() { | |
| if (iterator === undefined) { | |
| iterator = self[Symbol.iterator]() | |
| return { done: false, value: acc } | |
| } | |
| const result = iterator.next() | |
| if (result.done) { | |
| return result | |
| } | |
| acc = f(acc, result.value) | |
| return { done: false, value: acc } | |
| } | |
| return { next } | |
| } | |
| })) | |
| /** | |
| * Checks whether an `Iterable` is empty. | |
| * | |
| * **Example** (Checking for emptiness) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual(Iterable.isEmpty([]), true) | |
| * assert.deepStrictEqual(Iterable.isEmpty([1, 2, 3]), false) | |
| * ``` | |
| * | |
| * @category guards | |
| * @since 2.0.0 | |
| */ | |
| export const isEmpty = <A>(self: Iterable<A>): self is Iterable<never> => { | |
| const iterator = self[Symbol.iterator]() | |
| return iterator.next().done === true | |
| } | |
| /** | |
| * Returns the number of elements in a `Iterable`. | |
| * | |
| * **Example** (Counting iterable elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * console.log(Iterable.size(numbers)) // 5 | |
| * | |
| * const empty = Iterable.empty<number>() | |
| * console.log(Iterable.size(empty)) // 0 | |
| * | |
| * // Works with any iterable | |
| * const letters = "hello" | |
| * console.log(Iterable.size(letters)) // 5 | |
| * | |
| * // Note: This consumes the entire iterable | |
| * const range = Iterable.range(1, 100) | |
| * console.log(Iterable.size(range)) // 100 | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| export const size = <A>(self: Iterable<A>): number => { | |
| const iterator = self[Symbol.iterator]() | |
| let count = 0 | |
| while (!iterator.next().done) { | |
| count++ | |
| } | |
| return count | |
| } | |
| /** | |
| * Gets the first element of a `Iterable` safely, or `None` if the `Iterable` is empty. | |
| * | |
| * **Example** (Getting the first element) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * const numbers = [1, 2, 3] | |
| * console.log(Iterable.head(numbers)) // Option.some(1) | |
| * | |
| * const empty = Iterable.empty<number>() | |
| * console.log(Iterable.head(empty)) // Option.none() | |
| * | |
| * // Safe way to get first element | |
| * const firstEven = Iterable.head( | |
| * Iterable.filter([1, 3, 4, 5], (x) => x % 2 === 0) | |
| * ) | |
| * console.log(firstEven) // Option.some(4) | |
| * | |
| * // Use with Option methods | |
| * const doubled = Option.map(Iterable.head([5, 10, 15]), (x) => x * 2) | |
| * console.log(doubled) // Option.some(10) | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| export const head = <A>(self: Iterable<A>): Option<A> => { | |
| const iterator = self[Symbol.iterator]() | |
| const result = iterator.next() | |
| return result.done ? O.none() : O.some(result.value) | |
| } | |
| /** | |
| * Gets the first element of an `Iterable` without returning an `Option`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when the `Iterable` is known to be non-empty and direct access to the | |
| * first element is preferred over handling `Option.none`. | |
| * | |
| * **Gotchas** | |
| * | |
| * Throws if the `Iterable` is empty. | |
| * | |
| * **Example** (Getting the first element unsafely) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3] | |
| * console.log(Iterable.headUnsafe(numbers)) // 1 | |
| * | |
| * const letters = "hello" | |
| * console.log(Iterable.headUnsafe(letters)) // "h" | |
| * | |
| * // Iterable.headUnsafe(Iterable.empty<number>()) | |
| * // throws Error: "headUnsafe: empty iterable" | |
| * | |
| * // Use only when you're certain the iterable is non-empty | |
| * const nonEmpty = Iterable.range(1, 10) | |
| * console.log(Iterable.headUnsafe(nonEmpty)) // 1 | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 4.0.0 | |
| */ | |
| export const headUnsafe = <A>(self: Iterable<A>): A => { | |
| const iterator = self[Symbol.iterator]() | |
| const result = iterator.next() | |
| if (result.done) throw new Error("headUnsafe: empty iterable") | |
| return result.value | |
| } | |
| /** | |
| * Keeps only a max number of elements from the start of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to a non-negative integer. | |
| * | |
| * **Example** (Taking from the start) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const firstThree = Iterable.take(numbers, 3) | |
| * console.log(Array.from(firstThree)) // [1, 2, 3] | |
| * | |
| * // Taking more than available returns all elements | |
| * const firstTen = Iterable.take(numbers, 10) | |
| * console.log(Array.from(firstTen)) // [1, 2, 3, 4, 5] | |
| * | |
| * // Taking 0 or negative returns empty | |
| * const none = Iterable.take(numbers, 0) | |
| * console.log(Array.from(none)) // [] | |
| * | |
| * // Useful with infinite iterables | |
| * const naturals = Iterable.range(1) | |
| * const firstFive = Iterable.take(naturals, 5) | |
| * console.log(Array.from(firstFive)) // [1, 2, 3, 4, 5] | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| export const take: { | |
| /** | |
| * Keeps only a max number of elements from the start of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to a non-negative integer. | |
| * | |
| * **Example** (Taking from the start) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const firstThree = Iterable.take(numbers, 3) | |
| * console.log(Array.from(firstThree)) // [1, 2, 3] | |
| * | |
| * // Taking more than available returns all elements | |
| * const firstTen = Iterable.take(numbers, 10) | |
| * console.log(Array.from(firstTen)) // [1, 2, 3, 4, 5] | |
| * | |
| * // Taking 0 or negative returns empty | |
| * const none = Iterable.take(numbers, 0) | |
| * console.log(Array.from(none)) // [] | |
| * | |
| * // Useful with infinite iterables | |
| * const naturals = Iterable.range(1) | |
| * const firstFive = Iterable.take(naturals, 5) | |
| * console.log(Array.from(firstFive)) // [1, 2, 3, 4, 5] | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| (n: number): <A>(self: Iterable<A>) => Iterable<A> | |
| /** | |
| * Keeps only a max number of elements from the start of an `Iterable`, creating a new `Iterable`. | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to a non-negative integer. | |
| * | |
| * **Example** (Taking from the start) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const firstThree = Iterable.take(numbers, 3) | |
| * console.log(Array.from(firstThree)) // [1, 2, 3] | |
| * | |
| * // Taking more than available returns all elements | |
| * const firstTen = Iterable.take(numbers, 10) | |
| * console.log(Array.from(firstTen)) // [1, 2, 3, 4, 5] | |
| * | |
| * // Taking 0 or negative returns empty | |
| * const none = Iterable.take(numbers, 0) | |
| * console.log(Array.from(none)) // [] | |
| * | |
| * // Useful with infinite iterables | |
| * const naturals = Iterable.range(1) | |
| * const firstFive = Iterable.take(naturals, 5) | |
| * console.log(Array.from(firstFive)) // [1, 2, 3, 4, 5] | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, n: number): Iterable<A> | |
| } = dual(2, <A>(self: Iterable<A>, n: number): Iterable<A> => ({ | |
| [Symbol.iterator]() { | |
| let i = 0 | |
| const iterator = self[Symbol.iterator]() | |
| return { | |
| next() { | |
| if (i < n) { | |
| i++ | |
| return iterator.next() | |
| } | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| } | |
| })) | |
| /** | |
| * Takes the longest initial `Iterable` prefix for which all elements satisfy the | |
| * specified predicate. | |
| * | |
| * **Example** (Taking while a predicate holds) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [2, 4, 6, 8, 3, 10, 12] | |
| * const evenPrefix = Iterable.takeWhile(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evenPrefix)) // [2, 4, 6, 8] | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const firstThreeByIndex = Iterable.takeWhile(letters, (_, i) => i < 3) | |
| * console.log(Array.from(firstThreeByIndex)) // ["a", "b", "c"] | |
| * | |
| * // Stops at first non-matching element | |
| * const mixed = [1, 3, 5, 4, 7, 9] | |
| * const oddPrefix = Iterable.takeWhile(mixed, (x) => x % 2 === 1) | |
| * console.log(Array.from(oddPrefix)) // [1, 3, 5] | |
| * | |
| * // Type refinement | |
| * const values: Array<string | number> = ["a", "b", "c", 1, "d"] | |
| * const stringPrefix = Iterable.takeWhile( | |
| * values, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(stringPrefix)) // ["a", "b", "c"] (typed as string[]) | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| export const takeWhile: { | |
| /** | |
| * Takes the longest initial `Iterable` prefix for which all elements satisfy the | |
| * specified predicate. | |
| * | |
| * **Example** (Taking while a predicate holds) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [2, 4, 6, 8, 3, 10, 12] | |
| * const evenPrefix = Iterable.takeWhile(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evenPrefix)) // [2, 4, 6, 8] | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const firstThreeByIndex = Iterable.takeWhile(letters, (_, i) => i < 3) | |
| * console.log(Array.from(firstThreeByIndex)) // ["a", "b", "c"] | |
| * | |
| * // Stops at first non-matching element | |
| * const mixed = [1, 3, 5, 4, 7, 9] | |
| * const oddPrefix = Iterable.takeWhile(mixed, (x) => x % 2 === 1) | |
| * console.log(Array.from(oddPrefix)) // [1, 3, 5] | |
| * | |
| * // Type refinement | |
| * const values: Array<string | number> = ["a", "b", "c", 1, "d"] | |
| * const stringPrefix = Iterable.takeWhile( | |
| * values, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(stringPrefix)) // ["a", "b", "c"] (typed as string[]) | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Iterable<B> | |
| /** | |
| * Takes the longest initial `Iterable` prefix for which all elements satisfy the | |
| * specified predicate. | |
| * | |
| * **Example** (Taking while a predicate holds) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [2, 4, 6, 8, 3, 10, 12] | |
| * const evenPrefix = Iterable.takeWhile(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evenPrefix)) // [2, 4, 6, 8] | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const firstThreeByIndex = Iterable.takeWhile(letters, (_, i) => i < 3) | |
| * console.log(Array.from(firstThreeByIndex)) // ["a", "b", "c"] | |
| * | |
| * // Stops at first non-matching element | |
| * const mixed = [1, 3, 5, 4, 7, 9] | |
| * const oddPrefix = Iterable.takeWhile(mixed, (x) => x % 2 === 1) | |
| * console.log(Array.from(oddPrefix)) // [1, 3, 5] | |
| * | |
| * // Type refinement | |
| * const values: Array<string | number> = ["a", "b", "c", 1, "d"] | |
| * const stringPrefix = Iterable.takeWhile( | |
| * values, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(stringPrefix)) // ["a", "b", "c"] (typed as string[]) | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Iterable<A> | |
| /** | |
| * Takes the longest initial `Iterable` prefix for which all elements satisfy the | |
| * specified predicate. | |
| * | |
| * **Example** (Taking while a predicate holds) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [2, 4, 6, 8, 3, 10, 12] | |
| * const evenPrefix = Iterable.takeWhile(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evenPrefix)) // [2, 4, 6, 8] | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const firstThreeByIndex = Iterable.takeWhile(letters, (_, i) => i < 3) | |
| * console.log(Array.from(firstThreeByIndex)) // ["a", "b", "c"] | |
| * | |
| * // Stops at first non-matching element | |
| * const mixed = [1, 3, 5, 4, 7, 9] | |
| * const oddPrefix = Iterable.takeWhile(mixed, (x) => x % 2 === 1) | |
| * console.log(Array.from(oddPrefix)) // [1, 3, 5] | |
| * | |
| * // Type refinement | |
| * const values: Array<string | number> = ["a", "b", "c", 1, "d"] | |
| * const stringPrefix = Iterable.takeWhile( | |
| * values, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(stringPrefix)) // ["a", "b", "c"] (typed as string[]) | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Iterable<B> | |
| /** | |
| * Takes the longest initial `Iterable` prefix for which all elements satisfy the | |
| * specified predicate. | |
| * | |
| * **Example** (Taking while a predicate holds) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [2, 4, 6, 8, 3, 10, 12] | |
| * const evenPrefix = Iterable.takeWhile(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evenPrefix)) // [2, 4, 6, 8] | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const firstThreeByIndex = Iterable.takeWhile(letters, (_, i) => i < 3) | |
| * console.log(Array.from(firstThreeByIndex)) // ["a", "b", "c"] | |
| * | |
| * // Stops at first non-matching element | |
| * const mixed = [1, 3, 5, 4, 7, 9] | |
| * const oddPrefix = Iterable.takeWhile(mixed, (x) => x % 2 === 1) | |
| * console.log(Array.from(oddPrefix)) // [1, 3, 5] | |
| * | |
| * // Type refinement | |
| * const values: Array<string | number> = ["a", "b", "c", 1, "d"] | |
| * const stringPrefix = Iterable.takeWhile( | |
| * values, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(stringPrefix)) // ["a", "b", "c"] (typed as string[]) | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Iterable<A> | |
| } = dual(2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Iterable<A> => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let i = 0 | |
| return { | |
| next() { | |
| const result = iterator.next() | |
| if (result.done || !predicate(result.value, i++)) { | |
| return { done: true, value: undefined } | |
| } | |
| return result | |
| } | |
| } | |
| } | |
| })) | |
| /** | |
| * Drops a max number of elements from the start of an `Iterable` | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to a non-negative integer. | |
| * | |
| * **Example** (Dropping from the start) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const withoutFirstTwo = Iterable.drop(numbers, 2) | |
| * console.log(Array.from(withoutFirstTwo)) // [3, 4, 5] | |
| * | |
| * // Dropping more than available returns empty | |
| * const withoutFirstTen = Iterable.drop(numbers, 10) | |
| * console.log(Array.from(withoutFirstTen)) // [] | |
| * | |
| * // Dropping 0 or negative returns all elements | |
| * const all = Iterable.drop(numbers, 0) | |
| * console.log(Array.from(all)) // [1, 2, 3, 4, 5] | |
| * | |
| * // Combine with take for slicing | |
| * const slice = Iterable.take(Iterable.drop(numbers, 1), 3) | |
| * console.log(Array.from(slice)) // [2, 3, 4] | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| export const drop: { | |
| /** | |
| * Drops a max number of elements from the start of an `Iterable` | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to a non-negative integer. | |
| * | |
| * **Example** (Dropping from the start) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const withoutFirstTwo = Iterable.drop(numbers, 2) | |
| * console.log(Array.from(withoutFirstTwo)) // [3, 4, 5] | |
| * | |
| * // Dropping more than available returns empty | |
| * const withoutFirstTen = Iterable.drop(numbers, 10) | |
| * console.log(Array.from(withoutFirstTen)) // [] | |
| * | |
| * // Dropping 0 or negative returns all elements | |
| * const all = Iterable.drop(numbers, 0) | |
| * console.log(Array.from(all)) // [1, 2, 3, 4, 5] | |
| * | |
| * // Combine with take for slicing | |
| * const slice = Iterable.take(Iterable.drop(numbers, 1), 3) | |
| * console.log(Array.from(slice)) // [2, 3, 4] | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| (n: number): <A>(self: Iterable<A>) => Iterable<A> | |
| /** | |
| * Drops a max number of elements from the start of an `Iterable` | |
| * | |
| * **Details** | |
| * | |
| * `n` is normalized to a non-negative integer. | |
| * | |
| * **Example** (Dropping from the start) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const withoutFirstTwo = Iterable.drop(numbers, 2) | |
| * console.log(Array.from(withoutFirstTwo)) // [3, 4, 5] | |
| * | |
| * // Dropping more than available returns empty | |
| * const withoutFirstTen = Iterable.drop(numbers, 10) | |
| * console.log(Array.from(withoutFirstTen)) // [] | |
| * | |
| * // Dropping 0 or negative returns all elements | |
| * const all = Iterable.drop(numbers, 0) | |
| * console.log(Array.from(all)) // [1, 2, 3, 4, 5] | |
| * | |
| * // Combine with take for slicing | |
| * const slice = Iterable.take(Iterable.drop(numbers, 1), 3) | |
| * console.log(Array.from(slice)) // [2, 3, 4] | |
| * ``` | |
| * | |
| * @category getters | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, n: number): Iterable<A> | |
| } = dual(2, <A>(self: Iterable<A>, n: number): Iterable<A> => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let i = 0 | |
| return { | |
| next() { | |
| while (i < n) { | |
| const result = iterator.next() | |
| if (result.done) { | |
| return { done: true, value: undefined } | |
| } | |
| i++ | |
| } | |
| return iterator.next() | |
| } | |
| } | |
| } | |
| })) | |
| /** | |
| * Returns the first element that satisfies the specified | |
| * predicate, or `None` if no such element exists. | |
| * | |
| * **Example** (Finding the first match) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8] | |
| * const firstEven = Iterable.findFirst(numbers, (x) => x % 2 === 0) | |
| * console.log(firstEven) // Option.some(4) | |
| * | |
| * const firstGreaterThan10 = Iterable.findFirst(numbers, (x) => x > 10) | |
| * console.log(firstGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d"] | |
| * const atEvenIndex = Iterable.findFirst(letters, (_, i) => i % 2 === 0) | |
| * console.log(atEvenIndex) // Option.some("a") | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world"] | |
| * const firstString = Iterable.findFirst( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(firstString) // Option.some("hello") | |
| * | |
| * // Transform during search | |
| * const findSquareRoot = Iterable.findFirst([1, 4, 9, 16], (x) => { | |
| * const sqrt = Math.sqrt(x) | |
| * return Number.isInteger(sqrt) ? Option.some(sqrt) : Option.none() | |
| * }) | |
| * console.log(findSquareRoot) // Option.some(1) | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| export const findFirst: { | |
| /** | |
| * Returns the first element that satisfies the specified | |
| * predicate, or `None` if no such element exists. | |
| * | |
| * **Example** (Finding the first match) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8] | |
| * const firstEven = Iterable.findFirst(numbers, (x) => x % 2 === 0) | |
| * console.log(firstEven) // Option.some(4) | |
| * | |
| * const firstGreaterThan10 = Iterable.findFirst(numbers, (x) => x > 10) | |
| * console.log(firstGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d"] | |
| * const atEvenIndex = Iterable.findFirst(letters, (_, i) => i % 2 === 0) | |
| * console.log(atEvenIndex) // Option.some("a") | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world"] | |
| * const firstString = Iterable.findFirst( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(firstString) // Option.some("hello") | |
| * | |
| * // Transform during search | |
| * const findSquareRoot = Iterable.findFirst([1, 4, 9, 16], (x) => { | |
| * const sqrt = Math.sqrt(x) | |
| * return Number.isInteger(sqrt) ? Option.some(sqrt) : Option.none() | |
| * }) | |
| * console.log(findSquareRoot) // Option.some(1) | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(f: (a: NoInfer<A>, i: number) => Option<B>): (self: Iterable<A>) => Option<B> | |
| /** | |
| * Returns the first element that satisfies the specified | |
| * predicate, or `None` if no such element exists. | |
| * | |
| * **Example** (Finding the first match) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8] | |
| * const firstEven = Iterable.findFirst(numbers, (x) => x % 2 === 0) | |
| * console.log(firstEven) // Option.some(4) | |
| * | |
| * const firstGreaterThan10 = Iterable.findFirst(numbers, (x) => x > 10) | |
| * console.log(firstGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d"] | |
| * const atEvenIndex = Iterable.findFirst(letters, (_, i) => i % 2 === 0) | |
| * console.log(atEvenIndex) // Option.some("a") | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world"] | |
| * const firstString = Iterable.findFirst( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(firstString) // Option.some("hello") | |
| * | |
| * // Transform during search | |
| * const findSquareRoot = Iterable.findFirst([1, 4, 9, 16], (x) => { | |
| * const sqrt = Math.sqrt(x) | |
| * return Number.isInteger(sqrt) ? Option.some(sqrt) : Option.none() | |
| * }) | |
| * console.log(findSquareRoot) // Option.some(1) | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Option<B> | |
| /** | |
| * Returns the first element that satisfies the specified | |
| * predicate, or `None` if no such element exists. | |
| * | |
| * **Example** (Finding the first match) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8] | |
| * const firstEven = Iterable.findFirst(numbers, (x) => x % 2 === 0) | |
| * console.log(firstEven) // Option.some(4) | |
| * | |
| * const firstGreaterThan10 = Iterable.findFirst(numbers, (x) => x > 10) | |
| * console.log(firstGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d"] | |
| * const atEvenIndex = Iterable.findFirst(letters, (_, i) => i % 2 === 0) | |
| * console.log(atEvenIndex) // Option.some("a") | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world"] | |
| * const firstString = Iterable.findFirst( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(firstString) // Option.some("hello") | |
| * | |
| * // Transform during search | |
| * const findSquareRoot = Iterable.findFirst([1, 4, 9, 16], (x) => { | |
| * const sqrt = Math.sqrt(x) | |
| * return Number.isInteger(sqrt) ? Option.some(sqrt) : Option.none() | |
| * }) | |
| * console.log(findSquareRoot) // Option.some(1) | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option<A> | |
| /** | |
| * Returns the first element that satisfies the specified | |
| * predicate, or `None` if no such element exists. | |
| * | |
| * **Example** (Finding the first match) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8] | |
| * const firstEven = Iterable.findFirst(numbers, (x) => x % 2 === 0) | |
| * console.log(firstEven) // Option.some(4) | |
| * | |
| * const firstGreaterThan10 = Iterable.findFirst(numbers, (x) => x > 10) | |
| * console.log(firstGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d"] | |
| * const atEvenIndex = Iterable.findFirst(letters, (_, i) => i % 2 === 0) | |
| * console.log(atEvenIndex) // Option.some("a") | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world"] | |
| * const firstString = Iterable.findFirst( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(firstString) // Option.some("hello") | |
| * | |
| * // Transform during search | |
| * const findSquareRoot = Iterable.findFirst([1, 4, 9, 16], (x) => { | |
| * const sqrt = Math.sqrt(x) | |
| * return Number.isInteger(sqrt) ? Option.some(sqrt) : Option.none() | |
| * }) | |
| * console.log(findSquareRoot) // Option.some(1) | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, f: (a: A, i: number) => Option<B>): Option<B> | |
| /** | |
| * Returns the first element that satisfies the specified | |
| * predicate, or `None` if no such element exists. | |
| * | |
| * **Example** (Finding the first match) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8] | |
| * const firstEven = Iterable.findFirst(numbers, (x) => x % 2 === 0) | |
| * console.log(firstEven) // Option.some(4) | |
| * | |
| * const firstGreaterThan10 = Iterable.findFirst(numbers, (x) => x > 10) | |
| * console.log(firstGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d"] | |
| * const atEvenIndex = Iterable.findFirst(letters, (_, i) => i % 2 === 0) | |
| * console.log(atEvenIndex) // Option.some("a") | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world"] | |
| * const firstString = Iterable.findFirst( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(firstString) // Option.some("hello") | |
| * | |
| * // Transform during search | |
| * const findSquareRoot = Iterable.findFirst([1, 4, 9, 16], (x) => { | |
| * const sqrt = Math.sqrt(x) | |
| * return Number.isInteger(sqrt) ? Option.some(sqrt) : Option.none() | |
| * }) | |
| * console.log(findSquareRoot) // Option.some(1) | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Option<B> | |
| /** | |
| * Returns the first element that satisfies the specified | |
| * predicate, or `None` if no such element exists. | |
| * | |
| * **Example** (Finding the first match) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8] | |
| * const firstEven = Iterable.findFirst(numbers, (x) => x % 2 === 0) | |
| * console.log(firstEven) // Option.some(4) | |
| * | |
| * const firstGreaterThan10 = Iterable.findFirst(numbers, (x) => x > 10) | |
| * console.log(firstGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d"] | |
| * const atEvenIndex = Iterable.findFirst(letters, (_, i) => i % 2 === 0) | |
| * console.log(atEvenIndex) // Option.some("a") | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world"] | |
| * const firstString = Iterable.findFirst( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(firstString) // Option.some("hello") | |
| * | |
| * // Transform during search | |
| * const findSquareRoot = Iterable.findFirst([1, 4, 9, 16], (x) => { | |
| * const sqrt = Math.sqrt(x) | |
| * return Number.isInteger(sqrt) ? Option.some(sqrt) : Option.none() | |
| * }) | |
| * console.log(findSquareRoot) // Option.some(1) | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option<A> | |
| } = dual( | |
| 2, | |
| <A>(self: Iterable<A>, f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option<A>)): Option<A> => { | |
| let i = 0 | |
| for (const a of self) { | |
| const o = f(a, i) | |
| if (isBoolean(o)) { | |
| if (o) { | |
| return O.some(a) | |
| } | |
| } else { | |
| if (O.isSome(o)) { | |
| return o | |
| } | |
| } | |
| i++ | |
| } | |
| return O.none() | |
| } | |
| ) | |
| /** | |
| * Finds the last element for which a predicate holds. | |
| * | |
| * **Example** (Finding the last match) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8, 2] | |
| * const lastEven = Iterable.findLast(numbers, (x) => x % 2 === 0) | |
| * console.log(lastEven) // Option.some(2) | |
| * | |
| * const lastGreaterThan10 = Iterable.findLast(numbers, (x) => x > 10) | |
| * console.log(lastGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const lastAtEvenIndex = Iterable.findLast(letters, (_, i) => i % 2 === 0) | |
| * console.log(lastAtEvenIndex) // Option.some("e") (index 4) | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world", 3] | |
| * const lastString = Iterable.findLast( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(lastString) // Option.some("world") | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| export const findLast: { | |
| /** | |
| * Finds the last element for which a predicate holds. | |
| * | |
| * **Example** (Finding the last match) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8, 2] | |
| * const lastEven = Iterable.findLast(numbers, (x) => x % 2 === 0) | |
| * console.log(lastEven) // Option.some(2) | |
| * | |
| * const lastGreaterThan10 = Iterable.findLast(numbers, (x) => x > 10) | |
| * console.log(lastGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const lastAtEvenIndex = Iterable.findLast(letters, (_, i) => i % 2 === 0) | |
| * console.log(lastAtEvenIndex) // Option.some("e") (index 4) | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world", 3] | |
| * const lastString = Iterable.findLast( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(lastString) // Option.some("world") | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(f: (a: NoInfer<A>, i: number) => Option<B>): (self: Iterable<A>) => Option<B> | |
| /** | |
| * Finds the last element for which a predicate holds. | |
| * | |
| * **Example** (Finding the last match) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8, 2] | |
| * const lastEven = Iterable.findLast(numbers, (x) => x % 2 === 0) | |
| * console.log(lastEven) // Option.some(2) | |
| * | |
| * const lastGreaterThan10 = Iterable.findLast(numbers, (x) => x > 10) | |
| * console.log(lastGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const lastAtEvenIndex = Iterable.findLast(letters, (_, i) => i % 2 === 0) | |
| * console.log(lastAtEvenIndex) // Option.some("e") (index 4) | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world", 3] | |
| * const lastString = Iterable.findLast( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(lastString) // Option.some("world") | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Option<B> | |
| /** | |
| * Finds the last element for which a predicate holds. | |
| * | |
| * **Example** (Finding the last match) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8, 2] | |
| * const lastEven = Iterable.findLast(numbers, (x) => x % 2 === 0) | |
| * console.log(lastEven) // Option.some(2) | |
| * | |
| * const lastGreaterThan10 = Iterable.findLast(numbers, (x) => x > 10) | |
| * console.log(lastGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const lastAtEvenIndex = Iterable.findLast(letters, (_, i) => i % 2 === 0) | |
| * console.log(lastAtEvenIndex) // Option.some("e") (index 4) | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world", 3] | |
| * const lastString = Iterable.findLast( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(lastString) // Option.some("world") | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option<A> | |
| /** | |
| * Finds the last element for which a predicate holds. | |
| * | |
| * **Example** (Finding the last match) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8, 2] | |
| * const lastEven = Iterable.findLast(numbers, (x) => x % 2 === 0) | |
| * console.log(lastEven) // Option.some(2) | |
| * | |
| * const lastGreaterThan10 = Iterable.findLast(numbers, (x) => x > 10) | |
| * console.log(lastGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const lastAtEvenIndex = Iterable.findLast(letters, (_, i) => i % 2 === 0) | |
| * console.log(lastAtEvenIndex) // Option.some("e") (index 4) | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world", 3] | |
| * const lastString = Iterable.findLast( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(lastString) // Option.some("world") | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, f: (a: A, i: number) => Option<B>): Option<B> | |
| /** | |
| * Finds the last element for which a predicate holds. | |
| * | |
| * **Example** (Finding the last match) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8, 2] | |
| * const lastEven = Iterable.findLast(numbers, (x) => x % 2 === 0) | |
| * console.log(lastEven) // Option.some(2) | |
| * | |
| * const lastGreaterThan10 = Iterable.findLast(numbers, (x) => x > 10) | |
| * console.log(lastGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const lastAtEvenIndex = Iterable.findLast(letters, (_, i) => i % 2 === 0) | |
| * console.log(lastAtEvenIndex) // Option.some("e") (index 4) | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world", 3] | |
| * const lastString = Iterable.findLast( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(lastString) // Option.some("world") | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Option<B> | |
| /** | |
| * Finds the last element for which a predicate holds. | |
| * | |
| * **Example** (Finding the last match) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 4, 6, 8, 2] | |
| * const lastEven = Iterable.findLast(numbers, (x) => x % 2 === 0) | |
| * console.log(lastEven) // Option.some(2) | |
| * | |
| * const lastGreaterThan10 = Iterable.findLast(numbers, (x) => x > 10) | |
| * console.log(lastGreaterThan10) // Option.none() | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const lastAtEvenIndex = Iterable.findLast(letters, (_, i) => i % 2 === 0) | |
| * console.log(lastAtEvenIndex) // Option.some("e") (index 4) | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = [1, "hello", 2, "world", 3] | |
| * const lastString = Iterable.findLast( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(lastString) // Option.some("world") | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option<A> | |
| } = dual( | |
| 2, | |
| <A>(self: Iterable<A>, f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option<A>)): Option<A> => { | |
| let i = 0 | |
| let last: Option<A> = O.none() | |
| for (const a of self) { | |
| const o = f(a, i) | |
| if (isBoolean(o)) { | |
| if (o) { | |
| last = O.some(a) | |
| } | |
| } else { | |
| if (O.isSome(o)) { | |
| last = o | |
| } | |
| } | |
| i++ | |
| } | |
| return last | |
| } | |
| ) | |
| /** | |
| * Takes two `Iterable`s and returns an `Iterable` of corresponding pairs. | |
| * | |
| * **Example** (Zipping iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3] | |
| * const letters = ["a", "b", "c"] | |
| * const zipped = Iterable.zip(numbers, letters) | |
| * console.log(Array.from(zipped)) // [[1, "a"], [2, "b"], [3, "c"]] | |
| * | |
| * // Different lengths - shorter one determines result length | |
| * const short = [1, 2] | |
| * const long = ["a", "b", "c", "d"] | |
| * const partial = Iterable.zip(short, long) | |
| * console.log(Array.from(partial)) // [[1, "a"], [2, "b"]] | |
| * | |
| * // Works with any iterables | |
| * const range = Iterable.range(1, 3) | |
| * const word = "abc" | |
| * const mixed = Iterable.zip(range, word) | |
| * console.log(Array.from(mixed)) // [[1, "a"], [2, "b"], [3, "c"]] | |
| * | |
| * // Create indexed pairs | |
| * const values = ["apple", "banana", "cherry"] | |
| * const indices = Iterable.range(0, 2) | |
| * const indexed = Iterable.zip(indices, values) | |
| * console.log(Array.from(indexed)) // [[0, "apple"], [1, "banana"], [2, "cherry"]] | |
| * ``` | |
| * | |
| * @category zipping | |
| * @since 2.0.0 | |
| */ | |
| export const zip: { | |
| /** | |
| * Takes two `Iterable`s and returns an `Iterable` of corresponding pairs. | |
| * | |
| * **Example** (Zipping iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3] | |
| * const letters = ["a", "b", "c"] | |
| * const zipped = Iterable.zip(numbers, letters) | |
| * console.log(Array.from(zipped)) // [[1, "a"], [2, "b"], [3, "c"]] | |
| * | |
| * // Different lengths - shorter one determines result length | |
| * const short = [1, 2] | |
| * const long = ["a", "b", "c", "d"] | |
| * const partial = Iterable.zip(short, long) | |
| * console.log(Array.from(partial)) // [[1, "a"], [2, "b"]] | |
| * | |
| * // Works with any iterables | |
| * const range = Iterable.range(1, 3) | |
| * const word = "abc" | |
| * const mixed = Iterable.zip(range, word) | |
| * console.log(Array.from(mixed)) // [[1, "a"], [2, "b"], [3, "c"]] | |
| * | |
| * // Create indexed pairs | |
| * const values = ["apple", "banana", "cherry"] | |
| * const indices = Iterable.range(0, 2) | |
| * const indexed = Iterable.zip(indices, values) | |
| * console.log(Array.from(indexed)) // [[0, "apple"], [1, "banana"], [2, "cherry"]] | |
| * ``` | |
| * | |
| * @category zipping | |
| * @since 2.0.0 | |
| */ | |
| <B>(that: Iterable<B>): <A>(self: Iterable<A>) => Iterable<[A, B]> | |
| /** | |
| * Takes two `Iterable`s and returns an `Iterable` of corresponding pairs. | |
| * | |
| * **Example** (Zipping iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3] | |
| * const letters = ["a", "b", "c"] | |
| * const zipped = Iterable.zip(numbers, letters) | |
| * console.log(Array.from(zipped)) // [[1, "a"], [2, "b"], [3, "c"]] | |
| * | |
| * // Different lengths - shorter one determines result length | |
| * const short = [1, 2] | |
| * const long = ["a", "b", "c", "d"] | |
| * const partial = Iterable.zip(short, long) | |
| * console.log(Array.from(partial)) // [[1, "a"], [2, "b"]] | |
| * | |
| * // Works with any iterables | |
| * const range = Iterable.range(1, 3) | |
| * const word = "abc" | |
| * const mixed = Iterable.zip(range, word) | |
| * console.log(Array.from(mixed)) // [[1, "a"], [2, "b"], [3, "c"]] | |
| * | |
| * // Create indexed pairs | |
| * const values = ["apple", "banana", "cherry"] | |
| * const indices = Iterable.range(0, 2) | |
| * const indexed = Iterable.zip(indices, values) | |
| * console.log(Array.from(indexed)) // [[0, "apple"], [1, "banana"], [2, "cherry"]] | |
| * ``` | |
| * | |
| * @category zipping | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<[A, B]> | |
| } = dual( | |
| 2, | |
| <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<[A, B]> => zipWith(self, that, Tuple.make) | |
| ) | |
| /** | |
| * Applies a function to pairs of elements at the same index in two `Iterable`s, collecting the results. If one | |
| * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. | |
| * | |
| * **Example** (Zipping with a combining function) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Add corresponding elements | |
| * const a = [1, 2, 3, 4] | |
| * const b = [10, 20, 30, 40] | |
| * const sums = Iterable.zipWith(a, b, (x, y) => x + y) | |
| * console.log(Array.from(sums)) // [11, 22, 33, 44] | |
| * | |
| * // Combine strings | |
| * const firstNames = ["John", "Jane", "Bob"] | |
| * const lastNames = ["Doe", "Smith", "Johnson"] | |
| * const fullNames = Iterable.zipWith( | |
| * firstNames, | |
| * lastNames, | |
| * (first, last) => `${first} ${last}` | |
| * ) | |
| * console.log(Array.from(fullNames)) // ["John Doe", "Jane Smith", "Bob Johnson"] | |
| * | |
| * // Different lengths - stops at shorter | |
| * const short = [1, 2] | |
| * const long = ["a", "b", "c", "d"] | |
| * const combined = Iterable.zipWith( | |
| * short, | |
| * long, | |
| * (num, letter) => `${num}${letter}` | |
| * ) | |
| * console.log(Array.from(combined)) // ["1a", "2b"] | |
| * | |
| * // Complex transformations | |
| * const prices = [10.99, 25.50, 5.00] | |
| * const quantities = [2, 1, 3] | |
| * const totals = Iterable.zipWith(prices, quantities, (price, qty) => { | |
| * return Math.round(price * qty * 100) / 100 // round to 2 decimal places | |
| * }) | |
| * console.log(Array.from(totals)) // [21.98, 25.5, 15] | |
| * ``` | |
| * | |
| * @category zipping | |
| * @since 2.0.0 | |
| */ | |
| export const zipWith: { | |
| /** | |
| * Applies a function to pairs of elements at the same index in two `Iterable`s, collecting the results. If one | |
| * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. | |
| * | |
| * **Example** (Zipping with a combining function) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Add corresponding elements | |
| * const a = [1, 2, 3, 4] | |
| * const b = [10, 20, 30, 40] | |
| * const sums = Iterable.zipWith(a, b, (x, y) => x + y) | |
| * console.log(Array.from(sums)) // [11, 22, 33, 44] | |
| * | |
| * // Combine strings | |
| * const firstNames = ["John", "Jane", "Bob"] | |
| * const lastNames = ["Doe", "Smith", "Johnson"] | |
| * const fullNames = Iterable.zipWith( | |
| * firstNames, | |
| * lastNames, | |
| * (first, last) => `${first} ${last}` | |
| * ) | |
| * console.log(Array.from(fullNames)) // ["John Doe", "Jane Smith", "Bob Johnson"] | |
| * | |
| * // Different lengths - stops at shorter | |
| * const short = [1, 2] | |
| * const long = ["a", "b", "c", "d"] | |
| * const combined = Iterable.zipWith( | |
| * short, | |
| * long, | |
| * (num, letter) => `${num}${letter}` | |
| * ) | |
| * console.log(Array.from(combined)) // ["1a", "2b"] | |
| * | |
| * // Complex transformations | |
| * const prices = [10.99, 25.50, 5.00] | |
| * const quantities = [2, 1, 3] | |
| * const totals = Iterable.zipWith(prices, quantities, (price, qty) => { | |
| * return Math.round(price * qty * 100) / 100 // round to 2 decimal places | |
| * }) | |
| * console.log(Array.from(totals)) // [21.98, 25.5, 15] | |
| * ``` | |
| * | |
| * @category zipping | |
| * @since 2.0.0 | |
| */ | |
| <B, A, C>(that: Iterable<B>, f: (a: A, b: B) => C): (self: Iterable<A>) => Iterable<C> | |
| /** | |
| * Applies a function to pairs of elements at the same index in two `Iterable`s, collecting the results. If one | |
| * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. | |
| * | |
| * **Example** (Zipping with a combining function) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Add corresponding elements | |
| * const a = [1, 2, 3, 4] | |
| * const b = [10, 20, 30, 40] | |
| * const sums = Iterable.zipWith(a, b, (x, y) => x + y) | |
| * console.log(Array.from(sums)) // [11, 22, 33, 44] | |
| * | |
| * // Combine strings | |
| * const firstNames = ["John", "Jane", "Bob"] | |
| * const lastNames = ["Doe", "Smith", "Johnson"] | |
| * const fullNames = Iterable.zipWith( | |
| * firstNames, | |
| * lastNames, | |
| * (first, last) => `${first} ${last}` | |
| * ) | |
| * console.log(Array.from(fullNames)) // ["John Doe", "Jane Smith", "Bob Johnson"] | |
| * | |
| * // Different lengths - stops at shorter | |
| * const short = [1, 2] | |
| * const long = ["a", "b", "c", "d"] | |
| * const combined = Iterable.zipWith( | |
| * short, | |
| * long, | |
| * (num, letter) => `${num}${letter}` | |
| * ) | |
| * console.log(Array.from(combined)) // ["1a", "2b"] | |
| * | |
| * // Complex transformations | |
| * const prices = [10.99, 25.50, 5.00] | |
| * const quantities = [2, 1, 3] | |
| * const totals = Iterable.zipWith(prices, quantities, (price, qty) => { | |
| * return Math.round(price * qty * 100) / 100 // round to 2 decimal places | |
| * }) | |
| * console.log(Array.from(totals)) // [21.98, 25.5, 15] | |
| * ``` | |
| * | |
| * @category zipping | |
| * @since 2.0.0 | |
| */ | |
| <A, B, C>(self: Iterable<A>, that: Iterable<B>, f: (a: A, b: B) => C): Iterable<C> | |
| } = dual(3, <B, A, C>(self: Iterable<A>, that: Iterable<B>, f: (a: A, b: B) => C): Iterable<C> => ({ | |
| [Symbol.iterator]() { | |
| const selfIterator = self[Symbol.iterator]() | |
| const thatIterator = that[Symbol.iterator]() | |
| return { | |
| next() { | |
| const selfResult = selfIterator.next() | |
| const thatResult = thatIterator.next() | |
| if (selfResult.done || thatResult.done) { | |
| return { done: true, value: undefined } | |
| } | |
| return { done: false, value: f(selfResult.value, thatResult.value) } | |
| } | |
| } | |
| } | |
| })) | |
| /** | |
| * Places a separator between members of an `Iterable`. | |
| * | |
| * **When to use** | |
| * | |
| * Use to lazily insert a separator between adjacent values. | |
| * | |
| * **Details** | |
| * | |
| * If the input is a non-empty array, the result is also a non-empty array. | |
| * | |
| * **Example** (Interspersing separators) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Join numbers with separator | |
| * const numbers = [1, 2, 3, 4] | |
| * const withCommas = Iterable.intersperse(numbers, ",") | |
| * console.log(Array.from(withCommas)) // [1, ",", 2, ",", 3, ",", 4] | |
| * | |
| * // Join words with spaces | |
| * const words = ["hello", "world", "from", "effect"] | |
| * const sentence = Iterable.intersperse(words, " ") | |
| * console.log(Array.from(sentence).join("")) // "hello world from effect" | |
| * | |
| * // Empty iterable remains empty | |
| * const empty = Iterable.empty<string>() | |
| * const stillEmpty = Iterable.intersperse(empty, "-") | |
| * console.log(Array.from(stillEmpty)) // [] | |
| * | |
| * // Single element has no separators added | |
| * const single = [42] | |
| * const noSeparator = Iterable.intersperse(single, "|") | |
| * console.log(Array.from(noSeparator)) // [42] | |
| * | |
| * // Build CSS-like strings | |
| * const styles = ["color: red", "font-size: 14px", "margin: 10px"] | |
| * const css = Iterable.intersperse(styles, "; ") | |
| * console.log(Array.from(css).join("")) // "color: red; font-size: 14px; margin: 10px" | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| export const intersperse: { | |
| /** | |
| * Places a separator between members of an `Iterable`. | |
| * | |
| * **When to use** | |
| * | |
| * Use to lazily insert a separator between adjacent values. | |
| * | |
| * **Details** | |
| * | |
| * If the input is a non-empty array, the result is also a non-empty array. | |
| * | |
| * **Example** (Interspersing separators) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Join numbers with separator | |
| * const numbers = [1, 2, 3, 4] | |
| * const withCommas = Iterable.intersperse(numbers, ",") | |
| * console.log(Array.from(withCommas)) // [1, ",", 2, ",", 3, ",", 4] | |
| * | |
| * // Join words with spaces | |
| * const words = ["hello", "world", "from", "effect"] | |
| * const sentence = Iterable.intersperse(words, " ") | |
| * console.log(Array.from(sentence).join("")) // "hello world from effect" | |
| * | |
| * // Empty iterable remains empty | |
| * const empty = Iterable.empty<string>() | |
| * const stillEmpty = Iterable.intersperse(empty, "-") | |
| * console.log(Array.from(stillEmpty)) // [] | |
| * | |
| * // Single element has no separators added | |
| * const single = [42] | |
| * const noSeparator = Iterable.intersperse(single, "|") | |
| * console.log(Array.from(noSeparator)) // [42] | |
| * | |
| * // Build CSS-like strings | |
| * const styles = ["color: red", "font-size: 14px", "margin: 10px"] | |
| * const css = Iterable.intersperse(styles, "; ") | |
| * console.log(Array.from(css).join("")) // "color: red; font-size: 14px; margin: 10px" | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <B>(middle: B): <A>(self: Iterable<A>) => Iterable<A | B> | |
| /** | |
| * Places a separator between members of an `Iterable`. | |
| * | |
| * **When to use** | |
| * | |
| * Use to lazily insert a separator between adjacent values. | |
| * | |
| * **Details** | |
| * | |
| * If the input is a non-empty array, the result is also a non-empty array. | |
| * | |
| * **Example** (Interspersing separators) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Join numbers with separator | |
| * const numbers = [1, 2, 3, 4] | |
| * const withCommas = Iterable.intersperse(numbers, ",") | |
| * console.log(Array.from(withCommas)) // [1, ",", 2, ",", 3, ",", 4] | |
| * | |
| * // Join words with spaces | |
| * const words = ["hello", "world", "from", "effect"] | |
| * const sentence = Iterable.intersperse(words, " ") | |
| * console.log(Array.from(sentence).join("")) // "hello world from effect" | |
| * | |
| * // Empty iterable remains empty | |
| * const empty = Iterable.empty<string>() | |
| * const stillEmpty = Iterable.intersperse(empty, "-") | |
| * console.log(Array.from(stillEmpty)) // [] | |
| * | |
| * // Single element has no separators added | |
| * const single = [42] | |
| * const noSeparator = Iterable.intersperse(single, "|") | |
| * console.log(Array.from(noSeparator)) // [42] | |
| * | |
| * // Build CSS-like strings | |
| * const styles = ["color: red", "font-size: 14px", "margin: 10px"] | |
| * const css = Iterable.intersperse(styles, "; ") | |
| * console.log(Array.from(css).join("")) // "color: red; font-size: 14px; margin: 10px" | |
| * ``` | |
| * | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, middle: B): Iterable<A | B> | |
| } = dual(2, <A, B>(self: Iterable<A>, middle: B): Iterable<A | B> => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let next = iterator.next() | |
| let emitted = false | |
| return { | |
| next() { | |
| if (next.done) { | |
| return next | |
| } else if (emitted) { | |
| emitted = false | |
| return { done: false, value: middle } | |
| } | |
| emitted = true | |
| const result = next | |
| next = iterator.next() | |
| return result | |
| } | |
| } | |
| } | |
| })) | |
| /** | |
| * Returns a function that checks if an `Iterable` contains a given value using a provided `isEquivalent` function. | |
| * | |
| * **Example** (Checking membership with custom equivalence) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Custom equivalence for objects | |
| * const byId = (a: { id: number }, b: { id: number }) => a.id === b.id | |
| * const containsById = Iterable.containsWith(byId) | |
| * | |
| * const users = [{ id: 1 }, { id: 2 }] | |
| * const hasUser1 = containsById(users, { id: 1 }) | |
| * console.log(hasUser1) // true (same id) | |
| * | |
| * // Case-insensitive string comparison | |
| * const caseInsensitive = (a: string, b: string) => | |
| * a.toLowerCase() === b.toLowerCase() | |
| * const containsCaseInsensitive = Iterable.containsWith(caseInsensitive) | |
| * | |
| * const words = ["Hello", "World"] | |
| * const hasHello = containsCaseInsensitive(words, "hello") | |
| * console.log(hasHello) // true | |
| * | |
| * // Approximate number comparison | |
| * const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.1 | |
| * const containsApprox = Iterable.containsWith(approxEqual) | |
| * | |
| * const values = [1.0, 2.0, 3.0] | |
| * const hasAlmostTwo = containsApprox(values, 2.05) | |
| * console.log(hasAlmostTwo) // true | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| export const containsWith = <A>(isEquivalent: (self: A, that: A) => boolean): { | |
| (a: A): (self: Iterable<A>) => boolean | |
| (self: Iterable<A>, a: A): boolean | |
| } => | |
| dual(2, (self: Iterable<A>, a: A): boolean => { | |
| for (const i of self) { | |
| if (isEquivalent(a, i)) { | |
| return true | |
| } | |
| } | |
| return false | |
| }) | |
| /** | |
| * Checks whether an iterable contains a value using Effect's default `Equal` | |
| * equivalence. | |
| * | |
| * **Details** | |
| * | |
| * Can be called as `contains(self, value)` or curried as | |
| * `contains(value)(self)`. | |
| * | |
| * **Example** (Checking membership) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * console.log(Iterable.contains(numbers, 3)) // true | |
| * console.log(Iterable.contains(numbers, 6)) // false | |
| * | |
| * const letters = "hello" | |
| * console.log(Iterable.contains(letters, "l")) // true | |
| * console.log(Iterable.contains(letters, "x")) // false | |
| * | |
| * // Works with any iterable | |
| * const range = Iterable.range(1, 100) | |
| * console.log(Iterable.contains(range, 50)) // true | |
| * console.log(Iterable.contains(range, 150)) // false | |
| * | |
| * // Curried version | |
| * const containsThree = Iterable.contains(3) | |
| * console.log(containsThree([1, 2, 3])) // true | |
| * console.log(containsThree([4, 5, 6])) // false | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| export const contains: { | |
| /** | |
| * Checks whether an iterable contains a value using Effect's default `Equal` | |
| * equivalence. | |
| * | |
| * **Details** | |
| * | |
| * Can be called as `contains(self, value)` or curried as | |
| * `contains(value)(self)`. | |
| * | |
| * **Example** (Checking membership) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * console.log(Iterable.contains(numbers, 3)) // true | |
| * console.log(Iterable.contains(numbers, 6)) // false | |
| * | |
| * const letters = "hello" | |
| * console.log(Iterable.contains(letters, "l")) // true | |
| * console.log(Iterable.contains(letters, "x")) // false | |
| * | |
| * // Works with any iterable | |
| * const range = Iterable.range(1, 100) | |
| * console.log(Iterable.contains(range, 50)) // true | |
| * console.log(Iterable.contains(range, 150)) // false | |
| * | |
| * // Curried version | |
| * const containsThree = Iterable.contains(3) | |
| * console.log(containsThree([1, 2, 3])) // true | |
| * console.log(containsThree([4, 5, 6])) // false | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(a: A): (self: Iterable<A>) => boolean | |
| /** | |
| * Checks whether an iterable contains a value using Effect's default `Equal` | |
| * equivalence. | |
| * | |
| * **Details** | |
| * | |
| * Can be called as `contains(self, value)` or curried as | |
| * `contains(value)(self)`. | |
| * | |
| * **Example** (Checking membership) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * console.log(Iterable.contains(numbers, 3)) // true | |
| * console.log(Iterable.contains(numbers, 6)) // false | |
| * | |
| * const letters = "hello" | |
| * console.log(Iterable.contains(letters, "l")) // true | |
| * console.log(Iterable.contains(letters, "x")) // false | |
| * | |
| * // Works with any iterable | |
| * const range = Iterable.range(1, 100) | |
| * console.log(Iterable.contains(range, 50)) // true | |
| * console.log(Iterable.contains(range, 150)) // false | |
| * | |
| * // Curried version | |
| * const containsThree = Iterable.contains(3) | |
| * console.log(containsThree([1, 2, 3])) // true | |
| * console.log(containsThree([4, 5, 6])) // false | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, a: A): boolean | |
| } = containsWith(Equal.asEquivalence()) | |
| /** | |
| * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of | |
| * the `Iterable`. | |
| * | |
| * **Example** (Chunking an iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] | |
| * const chunks = Iterable.chunksOf(numbers, 3) | |
| * console.log(Array.from(chunks).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2, 3], [4, 5, 6], [7, 8, 9]] | |
| * | |
| * // Last chunk can be shorter | |
| * const uneven = [1, 2, 3, 4, 5, 6, 7] | |
| * const chunks2 = Iterable.chunksOf(uneven, 3) | |
| * console.log(Array.from(chunks2).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2, 3], [4, 5, 6], [7]] | |
| * | |
| * // Chunk size larger than iterable | |
| * const small = [1, 2] | |
| * const chunks3 = Iterable.chunksOf(small, 5) | |
| * console.log(Array.from(chunks3).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2]] | |
| * | |
| * // Process data in batches | |
| * const data = Iterable.range(1, 100) | |
| * const batches = Iterable.chunksOf(data, 10) | |
| * const batchSums = Iterable.map( | |
| * batches, | |
| * (batch) => Iterable.reduce(batch, 0, (sum, n) => sum + n) | |
| * ) | |
| * console.log(Array.from(Iterable.take(batchSums, 3))) // [55, 155, 255] | |
| * ``` | |
| * | |
| * @category splitting | |
| * @since 2.0.0 | |
| */ | |
| export const chunksOf: { | |
| /** | |
| * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of | |
| * the `Iterable`. | |
| * | |
| * **Example** (Chunking an iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] | |
| * const chunks = Iterable.chunksOf(numbers, 3) | |
| * console.log(Array.from(chunks).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2, 3], [4, 5, 6], [7, 8, 9]] | |
| * | |
| * // Last chunk can be shorter | |
| * const uneven = [1, 2, 3, 4, 5, 6, 7] | |
| * const chunks2 = Iterable.chunksOf(uneven, 3) | |
| * console.log(Array.from(chunks2).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2, 3], [4, 5, 6], [7]] | |
| * | |
| * // Chunk size larger than iterable | |
| * const small = [1, 2] | |
| * const chunks3 = Iterable.chunksOf(small, 5) | |
| * console.log(Array.from(chunks3).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2]] | |
| * | |
| * // Process data in batches | |
| * const data = Iterable.range(1, 100) | |
| * const batches = Iterable.chunksOf(data, 10) | |
| * const batchSums = Iterable.map( | |
| * batches, | |
| * (batch) => Iterable.reduce(batch, 0, (sum, n) => sum + n) | |
| * ) | |
| * console.log(Array.from(Iterable.take(batchSums, 3))) // [55, 155, 255] | |
| * ``` | |
| * | |
| * @category splitting | |
| * @since 2.0.0 | |
| */ | |
| (n: number): <A>(self: Iterable<A>) => Iterable<Array<A>> | |
| /** | |
| * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of | |
| * the `Iterable`. | |
| * | |
| * **Example** (Chunking an iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] | |
| * const chunks = Iterable.chunksOf(numbers, 3) | |
| * console.log(Array.from(chunks).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2, 3], [4, 5, 6], [7, 8, 9]] | |
| * | |
| * // Last chunk can be shorter | |
| * const uneven = [1, 2, 3, 4, 5, 6, 7] | |
| * const chunks2 = Iterable.chunksOf(uneven, 3) | |
| * console.log(Array.from(chunks2).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2, 3], [4, 5, 6], [7]] | |
| * | |
| * // Chunk size larger than iterable | |
| * const small = [1, 2] | |
| * const chunks3 = Iterable.chunksOf(small, 5) | |
| * console.log(Array.from(chunks3).map((chunk) => Array.from(chunk))) | |
| * // [[1, 2]] | |
| * | |
| * // Process data in batches | |
| * const data = Iterable.range(1, 100) | |
| * const batches = Iterable.chunksOf(data, 10) | |
| * const batchSums = Iterable.map( | |
| * batches, | |
| * (batch) => Iterable.reduce(batch, 0, (sum, n) => sum + n) | |
| * ) | |
| * console.log(Array.from(Iterable.take(batchSums, 3))) // [55, 155, 255] | |
| * ``` | |
| * | |
| * @category splitting | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, n: number): Iterable<Array<A>> | |
| } = dual(2, <A>(self: Iterable<A>, n: number): Iterable<Array<A>> => { | |
| const safeN = Math.max(1, Math.floor(n)) | |
| return ({ | |
| [Symbol.iterator]() { | |
| let iterator: Iterator<A> | undefined = self[Symbol.iterator]() | |
| return { | |
| next() { | |
| if (iterator === undefined) { | |
| return { done: true, value: undefined } | |
| } | |
| const chunk: Array<A> = [] | |
| for (let i = 0; i < safeN; i++) { | |
| const result = iterator.next() | |
| if (result.done) { | |
| iterator = undefined | |
| return chunk.length === 0 ? { done: true, value: undefined } : { done: false, value: chunk } | |
| } | |
| chunk.push(result.value) | |
| } | |
| return { done: false, value: chunk } | |
| } | |
| } | |
| } | |
| }) | |
| }) | |
| /** | |
| * Groups equal, consecutive elements of an `Iterable` into `NonEmptyArray`s using the provided `isEquivalent` function. | |
| * | |
| * **Example** (Grouping consecutive elements with custom equivalence) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Group consecutive equal numbers | |
| * const numbers = [1, 1, 2, 2, 2, 3, 1, 1] | |
| * const grouped = Iterable.groupWith(numbers, (a, b) => a === b) | |
| * console.log(Array.from(grouped)) | |
| * // [[1, 1], [2, 2, 2], [3], [1, 1]] | |
| * | |
| * // Case-insensitive grouping of strings | |
| * const words = ["Apple", "APPLE", "banana", "Banana", "cherry"] | |
| * const caseInsensitive = (a: string, b: string) => | |
| * a.toLowerCase() === b.toLowerCase() | |
| * const groupedWords = Iterable.groupWith(words, caseInsensitive) | |
| * console.log(Array.from(groupedWords)) | |
| * // [["Apple", "APPLE"], ["banana", "Banana"], ["cherry"]] | |
| * | |
| * // Group by approximate equality | |
| * const floats = [1.1, 1.12, 1.9, 2.01, 2.05, 3.5] | |
| * const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.2 | |
| * const groupedFloats = Iterable.groupWith(floats, approxEqual) | |
| * console.log(Array.from(groupedFloats)) | |
| * // [[1.1, 1.12], [1.9, 2.01, 2.05], [3.5]] | |
| * | |
| * // Only groups consecutive elements | |
| * const scattered = [1, 2, 1, 2, 1] | |
| * const scatteredGroups = Iterable.groupWith(scattered, (a, b) => a === b) | |
| * console.log(Array.from(scatteredGroups)) | |
| * // [[1], [2], [1], [2], [1]] (no grouping since none are consecutive) | |
| * ``` | |
| * | |
| * @category grouping | |
| * @since 2.0.0 | |
| */ | |
| export const groupWith: { | |
| /** | |
| * Groups equal, consecutive elements of an `Iterable` into `NonEmptyArray`s using the provided `isEquivalent` function. | |
| * | |
| * **Example** (Grouping consecutive elements with custom equivalence) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Group consecutive equal numbers | |
| * const numbers = [1, 1, 2, 2, 2, 3, 1, 1] | |
| * const grouped = Iterable.groupWith(numbers, (a, b) => a === b) | |
| * console.log(Array.from(grouped)) | |
| * // [[1, 1], [2, 2, 2], [3], [1, 1]] | |
| * | |
| * // Case-insensitive grouping of strings | |
| * const words = ["Apple", "APPLE", "banana", "Banana", "cherry"] | |
| * const caseInsensitive = (a: string, b: string) => | |
| * a.toLowerCase() === b.toLowerCase() | |
| * const groupedWords = Iterable.groupWith(words, caseInsensitive) | |
| * console.log(Array.from(groupedWords)) | |
| * // [["Apple", "APPLE"], ["banana", "Banana"], ["cherry"]] | |
| * | |
| * // Group by approximate equality | |
| * const floats = [1.1, 1.12, 1.9, 2.01, 2.05, 3.5] | |
| * const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.2 | |
| * const groupedFloats = Iterable.groupWith(floats, approxEqual) | |
| * console.log(Array.from(groupedFloats)) | |
| * // [[1.1, 1.12], [1.9, 2.01, 2.05], [3.5]] | |
| * | |
| * // Only groups consecutive elements | |
| * const scattered = [1, 2, 1, 2, 1] | |
| * const scatteredGroups = Iterable.groupWith(scattered, (a, b) => a === b) | |
| * console.log(Array.from(scatteredGroups)) | |
| * // [[1], [2], [1], [2], [1]] (no grouping since none are consecutive) | |
| * ``` | |
| * | |
| * @category grouping | |
| * @since 2.0.0 | |
| */ | |
| <A>(isEquivalent: (self: A, that: A) => boolean): (self: Iterable<A>) => Iterable<NonEmptyArray<A>> | |
| /** | |
| * Groups equal, consecutive elements of an `Iterable` into `NonEmptyArray`s using the provided `isEquivalent` function. | |
| * | |
| * **Example** (Grouping consecutive elements with custom equivalence) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Group consecutive equal numbers | |
| * const numbers = [1, 1, 2, 2, 2, 3, 1, 1] | |
| * const grouped = Iterable.groupWith(numbers, (a, b) => a === b) | |
| * console.log(Array.from(grouped)) | |
| * // [[1, 1], [2, 2, 2], [3], [1, 1]] | |
| * | |
| * // Case-insensitive grouping of strings | |
| * const words = ["Apple", "APPLE", "banana", "Banana", "cherry"] | |
| * const caseInsensitive = (a: string, b: string) => | |
| * a.toLowerCase() === b.toLowerCase() | |
| * const groupedWords = Iterable.groupWith(words, caseInsensitive) | |
| * console.log(Array.from(groupedWords)) | |
| * // [["Apple", "APPLE"], ["banana", "Banana"], ["cherry"]] | |
| * | |
| * // Group by approximate equality | |
| * const floats = [1.1, 1.12, 1.9, 2.01, 2.05, 3.5] | |
| * const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.2 | |
| * const groupedFloats = Iterable.groupWith(floats, approxEqual) | |
| * console.log(Array.from(groupedFloats)) | |
| * // [[1.1, 1.12], [1.9, 2.01, 2.05], [3.5]] | |
| * | |
| * // Only groups consecutive elements | |
| * const scattered = [1, 2, 1, 2, 1] | |
| * const scatteredGroups = Iterable.groupWith(scattered, (a, b) => a === b) | |
| * console.log(Array.from(scatteredGroups)) | |
| * // [[1], [2], [1], [2], [1]] (no grouping since none are consecutive) | |
| * ``` | |
| * | |
| * @category grouping | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<NonEmptyArray<A>> | |
| } = dual( | |
| 2, | |
| <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<NonEmptyArray<A>> => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let nextResult: IteratorResult<A> | undefined | |
| return { | |
| next() { | |
| let result: IteratorResult<A> | |
| if (nextResult !== undefined) { | |
| if (nextResult.done) { | |
| return { done: true, value: undefined } | |
| } | |
| result = nextResult | |
| nextResult = undefined | |
| } else { | |
| result = iterator.next() | |
| if (result.done) { | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| const chunk: NonEmptyArray<A> = [result.value] | |
| while (true) { | |
| const next = iterator.next() | |
| if (next.done || !isEquivalent(result.value, next.value)) { | |
| nextResult = next | |
| return { done: false, value: chunk } | |
| } | |
| chunk.push(next.value) | |
| } | |
| } | |
| } | |
| } | |
| }) | |
| ) | |
| /** | |
| * Groups equal, consecutive elements of an `Iterable` into `NonEmptyArray`s. | |
| * | |
| * **Example** (Grouping consecutive elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 1, 2, 2, 2, 3, 1, 1] | |
| * const grouped = Iterable.group(numbers) | |
| * console.log(Array.from(grouped)) | |
| * // [[1, 1], [2, 2, 2], [3], [1, 1]] | |
| * | |
| * const letters = "aabbccaa" | |
| * const groupedLetters = Iterable.group(letters) | |
| * console.log(Array.from(groupedLetters)) | |
| * // [["a", "a"], ["b", "b"], ["c", "c"], ["a", "a"]] | |
| * | |
| * // Works with objects using deep equality | |
| * const objects = [ | |
| * { type: "A", value: 1 }, | |
| * { type: "A", value: 1 }, | |
| * { type: "B", value: 2 }, | |
| * { type: "A", value: 1 } | |
| * ] | |
| * const groupedObjects = Iterable.group(objects) | |
| * console.log(Array.from(groupedObjects).length) // 3 groups | |
| * // Note: Only consecutive equal objects are grouped together | |
| * ``` | |
| * | |
| * @category grouping | |
| * @since 2.0.0 | |
| */ | |
| export const group: <A>(self: Iterable<A>) => Iterable<NonEmptyArray<A>> = groupWith( | |
| Equal.asEquivalence() | |
| ) | |
| /** | |
| * Groups all elements by the string or symbol key returned by `f`. | |
| * | |
| * **Details** | |
| * | |
| * Each property in the returned record contains a non-empty array of elements | |
| * that produced that key. Unlike `group`, matching elements do not need to be | |
| * consecutive. | |
| * | |
| * **Example** (Grouping by a key) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Group by string length | |
| * const words = ["a", "bb", "ccc", "dd", "eee", "f"] | |
| * const byLength = Iterable.groupBy(words, (word) => word.length.toString()) | |
| * console.log(byLength) | |
| * // { "1": ["a", "f"], "2": ["bb", "dd"], "3": ["ccc", "eee"] } | |
| * | |
| * // Group by first letter | |
| * const names = ["Alice", "Bob", "Charlie", "David", "Anna", "Betty"] | |
| * const byFirstLetter = Iterable.groupBy(names, (name) => name[0]) | |
| * console.log(byFirstLetter) | |
| * // { "A": ["Alice", "Anna"], "B": ["Bob", "Betty"], "C": ["Charlie"], "D": ["David"] } | |
| * | |
| * // Group by category | |
| * const items = [ | |
| * { name: "apple", category: "fruit" }, | |
| * { name: "carrot", category: "vegetable" }, | |
| * { name: "banana", category: "fruit" }, | |
| * { name: "broccoli", category: "vegetable" } | |
| * ] | |
| * const byCategory = Iterable.groupBy(items, (item) => item.category) | |
| * console.log(byCategory) | |
| * // { | |
| * // "fruit": [{ name: "apple", category: "fruit" }, { name: "banana", category: "fruit" }], | |
| * // "vegetable": [{ name: "carrot", category: "vegetable" }, { name: "broccoli", category: "vegetable" }] | |
| * // } | |
| * | |
| * // Group numbers by even/odd | |
| * const numbers = [1, 2, 3, 4, 5, 6] | |
| * const evenOdd = Iterable.groupBy(numbers, (n) => n % 2 === 0 ? "even" : "odd") | |
| * console.log(evenOdd) | |
| * // { "odd": [1, 3, 5], "even": [2, 4, 6] } | |
| * ``` | |
| * | |
| * @category grouping | |
| * @since 2.0.0 | |
| */ | |
| export const groupBy: { | |
| /** | |
| * Groups all elements by the string or symbol key returned by `f`. | |
| * | |
| * **Details** | |
| * | |
| * Each property in the returned record contains a non-empty array of elements | |
| * that produced that key. Unlike `group`, matching elements do not need to be | |
| * consecutive. | |
| * | |
| * **Example** (Grouping by a key) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Group by string length | |
| * const words = ["a", "bb", "ccc", "dd", "eee", "f"] | |
| * const byLength = Iterable.groupBy(words, (word) => word.length.toString()) | |
| * console.log(byLength) | |
| * // { "1": ["a", "f"], "2": ["bb", "dd"], "3": ["ccc", "eee"] } | |
| * | |
| * // Group by first letter | |
| * const names = ["Alice", "Bob", "Charlie", "David", "Anna", "Betty"] | |
| * const byFirstLetter = Iterable.groupBy(names, (name) => name[0]) | |
| * console.log(byFirstLetter) | |
| * // { "A": ["Alice", "Anna"], "B": ["Bob", "Betty"], "C": ["Charlie"], "D": ["David"] } | |
| * | |
| * // Group by category | |
| * const items = [ | |
| * { name: "apple", category: "fruit" }, | |
| * { name: "carrot", category: "vegetable" }, | |
| * { name: "banana", category: "fruit" }, | |
| * { name: "broccoli", category: "vegetable" } | |
| * ] | |
| * const byCategory = Iterable.groupBy(items, (item) => item.category) | |
| * console.log(byCategory) | |
| * // { | |
| * // "fruit": [{ name: "apple", category: "fruit" }, { name: "banana", category: "fruit" }], | |
| * // "vegetable": [{ name: "carrot", category: "vegetable" }, { name: "broccoli", category: "vegetable" }] | |
| * // } | |
| * | |
| * // Group numbers by even/odd | |
| * const numbers = [1, 2, 3, 4, 5, 6] | |
| * const evenOdd = Iterable.groupBy(numbers, (n) => n % 2 === 0 ? "even" : "odd") | |
| * console.log(evenOdd) | |
| * // { "odd": [1, 3, 5], "even": [2, 4, 6] } | |
| * ``` | |
| * | |
| * @category grouping | |
| * @since 2.0.0 | |
| */ | |
| <A, K extends string | symbol>(f: (a: A) => K): (self: Iterable<A>) => Record<Record.ReadonlyRecord.NonLiteralKey<K>, NonEmptyArray<A>> | |
| /** | |
| * Groups all elements by the string or symbol key returned by `f`. | |
| * | |
| * **Details** | |
| * | |
| * Each property in the returned record contains a non-empty array of elements | |
| * that produced that key. Unlike `group`, matching elements do not need to be | |
| * consecutive. | |
| * | |
| * **Example** (Grouping by a key) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Group by string length | |
| * const words = ["a", "bb", "ccc", "dd", "eee", "f"] | |
| * const byLength = Iterable.groupBy(words, (word) => word.length.toString()) | |
| * console.log(byLength) | |
| * // { "1": ["a", "f"], "2": ["bb", "dd"], "3": ["ccc", "eee"] } | |
| * | |
| * // Group by first letter | |
| * const names = ["Alice", "Bob", "Charlie", "David", "Anna", "Betty"] | |
| * const byFirstLetter = Iterable.groupBy(names, (name) => name[0]) | |
| * console.log(byFirstLetter) | |
| * // { "A": ["Alice", "Anna"], "B": ["Bob", "Betty"], "C": ["Charlie"], "D": ["David"] } | |
| * | |
| * // Group by category | |
| * const items = [ | |
| * { name: "apple", category: "fruit" }, | |
| * { name: "carrot", category: "vegetable" }, | |
| * { name: "banana", category: "fruit" }, | |
| * { name: "broccoli", category: "vegetable" } | |
| * ] | |
| * const byCategory = Iterable.groupBy(items, (item) => item.category) | |
| * console.log(byCategory) | |
| * // { | |
| * // "fruit": [{ name: "apple", category: "fruit" }, { name: "banana", category: "fruit" }], | |
| * // "vegetable": [{ name: "carrot", category: "vegetable" }, { name: "broccoli", category: "vegetable" }] | |
| * // } | |
| * | |
| * // Group numbers by even/odd | |
| * const numbers = [1, 2, 3, 4, 5, 6] | |
| * const evenOdd = Iterable.groupBy(numbers, (n) => n % 2 === 0 ? "even" : "odd") | |
| * console.log(evenOdd) | |
| * // { "odd": [1, 3, 5], "even": [2, 4, 6] } | |
| * ``` | |
| * | |
| * @category grouping | |
| * @since 2.0.0 | |
| */ | |
| <A, K extends string | symbol>(self: Iterable<A>, f: (a: A) => K): Record<Record.ReadonlyRecord.NonLiteralKey<K>, NonEmptyArray<A>> | |
| } = dual(2, <A, K extends string | symbol>( | |
| self: Iterable<A>, | |
| f: (a: A) => K | |
| ): Record<Record.ReadonlyRecord.NonLiteralKey<K>, NonEmptyArray<A>> => { | |
| const out: Record<string | symbol, NonEmptyArray<A>> = {} | |
| for (const a of self) { | |
| const k = f(a) | |
| if (Object.hasOwn(out, k)) { | |
| out[k].push(a) | |
| } else { | |
| out[k] = [a] | |
| } | |
| } | |
| return out | |
| }) | |
| const constEmpty: Iterable<never> = { | |
| [Symbol.iterator]() { | |
| return constEmptyIterator | |
| } | |
| } | |
| const constEmptyIterator: Iterator<never> = { | |
| next() { | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| /** | |
| * Creates an empty iterable that yields no elements. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need an empty iterable as a typed "no data" value or a base | |
| * case for iterable operations. | |
| * | |
| * **Example** (Creating an empty iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const empty = Iterable.empty<string>() | |
| * console.log(Array.from(empty)) // [] | |
| * console.log(Iterable.isEmpty(empty)) // true | |
| * | |
| * // Useful as base case for reductions | |
| * const hasData = true | |
| * const result = hasData | |
| * ? Iterable.range(1, 5) | |
| * : Iterable.empty<number>() | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| export const empty = <A = never>(): Iterable<A> => constEmpty | |
| /** | |
| * Creates an iterable containing a single element. | |
| * | |
| * **When to use** | |
| * | |
| * Use to wrap a single value in an iterable context so it can be combined | |
| * with other iterable operations. | |
| * | |
| * **Example** (Wrapping a single value) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const single = Iterable.of(42) | |
| * console.log(Array.from(single)) // [42] | |
| * | |
| * // Useful for creating homogeneous sequences | |
| * const sequences = [ | |
| * Iterable.of("hello"), | |
| * Iterable.range(1, 3), | |
| * Iterable.empty<string>() | |
| * ] | |
| * | |
| * // Can be used with flatMap for conditional inclusion | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const evensOnly = Iterable.flatMap( | |
| * numbers, | |
| * (n) => n % 2 === 0 ? Iterable.of(n) : Iterable.empty() | |
| * ) | |
| * console.log(Array.from(evensOnly)) // [2, 4] | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| export const of = <A>(a: A): Iterable<A> => [a] | |
| /** | |
| * Transforms each element of an iterable using a function. | |
| * | |
| * **Details** | |
| * | |
| * This is one of the most fundamental operations for working with iterables. | |
| * It applies a transformation function to each element, creating a new iterable | |
| * with the transformed values. The operation is lazy, so elements are only | |
| * transformed when the iterable is consumed. | |
| * | |
| * **Example** (Mapping elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Transform numbers to their squares | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const squares = Iterable.map(numbers, (x) => x * x) | |
| * console.log(Array.from(squares)) // [1, 4, 9, 16, 25] | |
| * | |
| * // Use index in transformation | |
| * const indexed = Iterable.map(["a", "b", "c"], (char, i) => `${i}: ${char}`) | |
| * console.log(Array.from(indexed)) // ["0: a", "1: b", "2: c"] | |
| * | |
| * // Chain transformations | |
| * const result = Iterable.map( | |
| * Iterable.map([1, 2, 3], (x) => x * 2), | |
| * (x) => x + 1 | |
| * ) | |
| * console.log(Array.from(result)) // [3, 5, 7] | |
| * ``` | |
| * | |
| * @category mapping | |
| * @since 2.0.0 | |
| */ | |
| export const map: { | |
| /** | |
| * Transforms each element of an iterable using a function. | |
| * | |
| * **Details** | |
| * | |
| * This is one of the most fundamental operations for working with iterables. | |
| * It applies a transformation function to each element, creating a new iterable | |
| * with the transformed values. The operation is lazy, so elements are only | |
| * transformed when the iterable is consumed. | |
| * | |
| * **Example** (Mapping elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Transform numbers to their squares | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const squares = Iterable.map(numbers, (x) => x * x) | |
| * console.log(Array.from(squares)) // [1, 4, 9, 16, 25] | |
| * | |
| * // Use index in transformation | |
| * const indexed = Iterable.map(["a", "b", "c"], (char, i) => `${i}: ${char}`) | |
| * console.log(Array.from(indexed)) // ["0: a", "1: b", "2: c"] | |
| * | |
| * // Chain transformations | |
| * const result = Iterable.map( | |
| * Iterable.map([1, 2, 3], (x) => x * 2), | |
| * (x) => x + 1 | |
| * ) | |
| * console.log(Array.from(result)) // [3, 5, 7] | |
| * ``` | |
| * | |
| * @category mapping | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(f: (a: NoInfer<A>, i: number) => B): (self: Iterable<A>) => Iterable<B> | |
| /** | |
| * Transforms each element of an iterable using a function. | |
| * | |
| * **Details** | |
| * | |
| * This is one of the most fundamental operations for working with iterables. | |
| * It applies a transformation function to each element, creating a new iterable | |
| * with the transformed values. The operation is lazy, so elements are only | |
| * transformed when the iterable is consumed. | |
| * | |
| * **Example** (Mapping elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Transform numbers to their squares | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const squares = Iterable.map(numbers, (x) => x * x) | |
| * console.log(Array.from(squares)) // [1, 4, 9, 16, 25] | |
| * | |
| * // Use index in transformation | |
| * const indexed = Iterable.map(["a", "b", "c"], (char, i) => `${i}: ${char}`) | |
| * console.log(Array.from(indexed)) // ["0: a", "1: b", "2: c"] | |
| * | |
| * // Chain transformations | |
| * const result = Iterable.map( | |
| * Iterable.map([1, 2, 3], (x) => x * 2), | |
| * (x) => x + 1 | |
| * ) | |
| * console.log(Array.from(result)) // [3, 5, 7] | |
| * ``` | |
| * | |
| * @category mapping | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, f: (a: NoInfer<A>, i: number) => B): Iterable<B> | |
| } = dual(2, <A, B>(self: Iterable<A>, f: (a: A, i: number) => B): Iterable<B> => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let i = 0 | |
| return { | |
| next() { | |
| const result = iterator.next() | |
| if (result.done) { | |
| return { done: true, value: undefined } | |
| } | |
| return { done: false, value: f(result.value, i++) } | |
| } | |
| } | |
| } | |
| })) | |
| /** | |
| * Applies a function to each element in an Iterable and returns a new Iterable containing the concatenated mapped elements. | |
| * | |
| * **Example** (FlatMapping iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Expand each number to a range | |
| * const numbers = [1, 2, 3] | |
| * const expanded = Iterable.flatMap(numbers, (n) => Iterable.range(1, n)) | |
| * console.log(Array.from(expanded)) // [1, 1, 2, 1, 2, 3] | |
| * | |
| * // Split strings into characters | |
| * const words = ["hi", "bye"] | |
| * const chars = Iterable.flatMap(words, (word) => word) | |
| * console.log(Array.from(chars)) // ["h", "i", "b", "y", "e"] | |
| * | |
| * // Conditional expansion with empty iterables | |
| * const values = [1, 2, 3, 4, 5] | |
| * const evenMultiples = Iterable.flatMap( | |
| * values, | |
| * (n) => n % 2 === 0 ? [n, n * 2, n * 3] : [] | |
| * ) | |
| * console.log(Array.from(evenMultiples)) // [2, 4, 6, 4, 8, 12] | |
| * | |
| * // Use index in transformation | |
| * const letters = ["a", "b", "c"] | |
| * const indexed = Iterable.flatMap( | |
| * letters, | |
| * (letter, i) => Iterable.replicate(letter, i + 1) | |
| * ) | |
| * console.log(Array.from(indexed)) // ["a", "b", "b", "c", "c", "c"] | |
| * ``` | |
| * | |
| * @category sequencing | |
| * @since 2.0.0 | |
| */ | |
| export const flatMap: { | |
| /** | |
| * Applies a function to each element in an Iterable and returns a new Iterable containing the concatenated mapped elements. | |
| * | |
| * **Example** (FlatMapping iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Expand each number to a range | |
| * const numbers = [1, 2, 3] | |
| * const expanded = Iterable.flatMap(numbers, (n) => Iterable.range(1, n)) | |
| * console.log(Array.from(expanded)) // [1, 1, 2, 1, 2, 3] | |
| * | |
| * // Split strings into characters | |
| * const words = ["hi", "bye"] | |
| * const chars = Iterable.flatMap(words, (word) => word) | |
| * console.log(Array.from(chars)) // ["h", "i", "b", "y", "e"] | |
| * | |
| * // Conditional expansion with empty iterables | |
| * const values = [1, 2, 3, 4, 5] | |
| * const evenMultiples = Iterable.flatMap( | |
| * values, | |
| * (n) => n % 2 === 0 ? [n, n * 2, n * 3] : [] | |
| * ) | |
| * console.log(Array.from(evenMultiples)) // [2, 4, 6, 4, 8, 12] | |
| * | |
| * // Use index in transformation | |
| * const letters = ["a", "b", "c"] | |
| * const indexed = Iterable.flatMap( | |
| * letters, | |
| * (letter, i) => Iterable.replicate(letter, i + 1) | |
| * ) | |
| * console.log(Array.from(indexed)) // ["a", "b", "b", "c", "c", "c"] | |
| * ``` | |
| * | |
| * @category sequencing | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(f: (a: NoInfer<A>, i: number) => Iterable<B>): (self: Iterable<A>) => Iterable<B> | |
| /** | |
| * Applies a function to each element in an Iterable and returns a new Iterable containing the concatenated mapped elements. | |
| * | |
| * **Example** (FlatMapping iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Expand each number to a range | |
| * const numbers = [1, 2, 3] | |
| * const expanded = Iterable.flatMap(numbers, (n) => Iterable.range(1, n)) | |
| * console.log(Array.from(expanded)) // [1, 1, 2, 1, 2, 3] | |
| * | |
| * // Split strings into characters | |
| * const words = ["hi", "bye"] | |
| * const chars = Iterable.flatMap(words, (word) => word) | |
| * console.log(Array.from(chars)) // ["h", "i", "b", "y", "e"] | |
| * | |
| * // Conditional expansion with empty iterables | |
| * const values = [1, 2, 3, 4, 5] | |
| * const evenMultiples = Iterable.flatMap( | |
| * values, | |
| * (n) => n % 2 === 0 ? [n, n * 2, n * 3] : [] | |
| * ) | |
| * console.log(Array.from(evenMultiples)) // [2, 4, 6, 4, 8, 12] | |
| * | |
| * // Use index in transformation | |
| * const letters = ["a", "b", "c"] | |
| * const indexed = Iterable.flatMap( | |
| * letters, | |
| * (letter, i) => Iterable.replicate(letter, i + 1) | |
| * ) | |
| * console.log(Array.from(indexed)) // ["a", "b", "b", "c", "c", "c"] | |
| * ``` | |
| * | |
| * @category sequencing | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, f: (a: NoInfer<A>, i: number) => Iterable<B>): Iterable<B> | |
| } = dual( | |
| 2, | |
| <A, B>(self: Iterable<A>, f: (a: A, i: number) => Iterable<B>): Iterable<B> => flatten(map(self, f)) | |
| ) | |
| /** | |
| * Flattens an Iterable of Iterables into a single Iterable | |
| * | |
| * **Example** (Flattening nested iterables) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Flatten nested arrays | |
| * const nested = [[1, 2], [3, 4], [5, 6]] | |
| * const flat = Iterable.flatten(nested) | |
| * console.log(Array.from(flat)) // [1, 2, 3, 4, 5, 6] | |
| * | |
| * // Flatten different iterable types | |
| * const mixed: Array<Iterable<string>> = ["ab", "cd"] | |
| * const flatMixed = Iterable.flatten(mixed) | |
| * console.log(Array.from(flatMixed)) // ["a", "b", "c", "d"] | |
| * | |
| * // Flatten deeply nested (only one level) | |
| * const deepNested = [[[1, 2]], [[3, 4]]] | |
| * const oneLevelFlat = Iterable.flatten(deepNested) | |
| * console.log(Array.from(oneLevelFlat).map((arr) => Array.from(arr))) | |
| * // [[1, 2], [3, 4]] (still contains arrays) | |
| * | |
| * // Empty iterables are handled correctly | |
| * const withEmpty = [[1, 2], [], [3, 4], []] | |
| * const flatWithEmpty = Iterable.flatten(withEmpty) | |
| * console.log(Array.from(flatWithEmpty)) // [1, 2, 3, 4] | |
| * ``` | |
| * | |
| * @category sequencing | |
| * @since 2.0.0 | |
| */ | |
| export const flatten = <A>(self: Iterable<Iterable<A>>): Iterable<A> => ({ | |
| [Symbol.iterator]() { | |
| const outerIterator = self[Symbol.iterator]() | |
| let innerIterator: Iterator<A> | undefined | |
| function next() { | |
| if (innerIterator === undefined) { | |
| const next = outerIterator.next() | |
| if (next.done) { | |
| return next | |
| } | |
| innerIterator = next.value[Symbol.iterator]() | |
| } | |
| const result = innerIterator.next() | |
| if (result.done) { | |
| innerIterator = undefined | |
| return next() | |
| } | |
| return result | |
| } | |
| return { next } | |
| } | |
| }) | |
| /** | |
| * Transforms elements of an iterable using a function that returns a `Result`, keeping only successful values. | |
| * | |
| * **Details** | |
| * | |
| * This combines mapping and filtering in a single operation. The function is | |
| * applied to each element, and only elements that result in `Result.succeed` | |
| * are included in the result. | |
| * | |
| * **Example** (Filtering and transforming Result values) | |
| * | |
| * ```ts | |
| * import { Iterable, Result } from "effect" | |
| * | |
| * // Parse strings to numbers, keeping only valid ones | |
| * const strings = ["1", "2", "invalid", "4", "not-a-number"] | |
| * const numbers = Iterable.filterMap(strings, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? Result.failVoid : Result.succeed(num) | |
| * }) | |
| * console.log(Array.from(numbers)) // [1, 2, 4] | |
| * | |
| * // Extract specific properties from objects | |
| * const users = [ | |
| * { name: "Alice", age: 25, email: "alice@example.com" }, | |
| * { name: "Bob", age: 17, email: undefined }, | |
| * { name: "Charlie", age: 30, email: "charlie@example.com" }, | |
| * { name: "David", age: 16, email: undefined } | |
| * ] | |
| * const adultEmails = Iterable.filterMap( | |
| * users, | |
| * (user) => | |
| * user.age >= 18 && user.email ? Result.succeed(user.email) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(adultEmails)) // ["alice@example.com", "charlie@example.com"] | |
| * | |
| * // Use index in transformation | |
| * const items = ["a", "b", "c", "d", "e"] | |
| * const evenIndexItems = Iterable.filterMap( | |
| * items, | |
| * (item, i) => i % 2 === 0 ? Result.succeed(`${i}: ${item}`) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(evenIndexItems)) // ["0: a", "2: c", "4: e"] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| export const filterMap: { | |
| /** | |
| * Transforms elements of an iterable using a function that returns a `Result`, keeping only successful values. | |
| * | |
| * **Details** | |
| * | |
| * This combines mapping and filtering in a single operation. The function is | |
| * applied to each element, and only elements that result in `Result.succeed` | |
| * are included in the result. | |
| * | |
| * **Example** (Filtering and transforming Result values) | |
| * | |
| * ```ts | |
| * import { Iterable, Result } from "effect" | |
| * | |
| * // Parse strings to numbers, keeping only valid ones | |
| * const strings = ["1", "2", "invalid", "4", "not-a-number"] | |
| * const numbers = Iterable.filterMap(strings, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? Result.failVoid : Result.succeed(num) | |
| * }) | |
| * console.log(Array.from(numbers)) // [1, 2, 4] | |
| * | |
| * // Extract specific properties from objects | |
| * const users = [ | |
| * { name: "Alice", age: 25, email: "alice@example.com" }, | |
| * { name: "Bob", age: 17, email: undefined }, | |
| * { name: "Charlie", age: 30, email: "charlie@example.com" }, | |
| * { name: "David", age: 16, email: undefined } | |
| * ] | |
| * const adultEmails = Iterable.filterMap( | |
| * users, | |
| * (user) => | |
| * user.age >= 18 && user.email ? Result.succeed(user.email) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(adultEmails)) // ["alice@example.com", "charlie@example.com"] | |
| * | |
| * // Use index in transformation | |
| * const items = ["a", "b", "c", "d", "e"] | |
| * const evenIndexItems = Iterable.filterMap( | |
| * items, | |
| * (item, i) => i % 2 === 0 ? Result.succeed(`${i}: ${item}`) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(evenIndexItems)) // ["0: a", "2: c", "4: e"] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A, B, X>(f: (input: A, i: number) => Result<B, X>): (self: Iterable<A>) => Iterable<B> | |
| /** | |
| * Transforms elements of an iterable using a function that returns a `Result`, keeping only successful values. | |
| * | |
| * **Details** | |
| * | |
| * This combines mapping and filtering in a single operation. The function is | |
| * applied to each element, and only elements that result in `Result.succeed` | |
| * are included in the result. | |
| * | |
| * **Example** (Filtering and transforming Result values) | |
| * | |
| * ```ts | |
| * import { Iterable, Result } from "effect" | |
| * | |
| * // Parse strings to numbers, keeping only valid ones | |
| * const strings = ["1", "2", "invalid", "4", "not-a-number"] | |
| * const numbers = Iterable.filterMap(strings, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? Result.failVoid : Result.succeed(num) | |
| * }) | |
| * console.log(Array.from(numbers)) // [1, 2, 4] | |
| * | |
| * // Extract specific properties from objects | |
| * const users = [ | |
| * { name: "Alice", age: 25, email: "alice@example.com" }, | |
| * { name: "Bob", age: 17, email: undefined }, | |
| * { name: "Charlie", age: 30, email: "charlie@example.com" }, | |
| * { name: "David", age: 16, email: undefined } | |
| * ] | |
| * const adultEmails = Iterable.filterMap( | |
| * users, | |
| * (user) => | |
| * user.age >= 18 && user.email ? Result.succeed(user.email) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(adultEmails)) // ["alice@example.com", "charlie@example.com"] | |
| * | |
| * // Use index in transformation | |
| * const items = ["a", "b", "c", "d", "e"] | |
| * const evenIndexItems = Iterable.filterMap( | |
| * items, | |
| * (item, i) => i % 2 === 0 ? Result.succeed(`${i}: ${item}`) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(evenIndexItems)) // ["0: a", "2: c", "4: e"] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A, B, X>(self: Iterable<A>, f: (input: A, i: number) => Result<B, X>): Iterable<B> | |
| } = dual( | |
| 2, | |
| <A, B, X>(self: Iterable<A>, f: (input: A, i: number) => Result<B, X>): Iterable<B> => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let i = 0 | |
| return { | |
| next() { | |
| let result = iterator.next() | |
| while (!result.done) { | |
| const next = f(result.value, i++) | |
| if (R.isSuccess(next)) { | |
| return { done: false, value: next.success } | |
| } | |
| result = iterator.next() | |
| } | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| } | |
| }) | |
| ) | |
| /** | |
| * Transforms all elements of the `Iterable` for as long as the specified function succeeds. | |
| * | |
| * **Example** (Filtering and transforming until failure) | |
| * | |
| * ```ts | |
| * import { Iterable, Result } from "effect" | |
| * | |
| * // Parse numbers until we hit an invalid one | |
| * const strings = ["1", "2", "3", "invalid", "4", "5"] | |
| * const numbers = Iterable.filterMapWhile(strings, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? Result.failVoid : Result.succeed(num) | |
| * }) | |
| * console.log(Array.from(numbers)) // [1, 2, 3] (stops at "invalid") | |
| * | |
| * // Take elements while they meet a condition and transform them | |
| * const values = [2, 4, 6, 7, 8, 10] | |
| * const doubledEvens = Iterable.filterMapWhile( | |
| * values, | |
| * (n) => n % 2 === 0 ? Result.succeed(n * 2) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(doubledEvens)) // [4, 8, 12] (stops at 7) | |
| * | |
| * // Process with index until condition fails | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const indexedUntilC = Iterable.filterMapWhile( | |
| * letters, | |
| * (letter, i) => letter !== "c" ? Result.succeed(`${i}: ${letter}`) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(indexedUntilC)) // ["0: a", "1: b"] (stops at "c") | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| export const filterMapWhile: { | |
| /** | |
| * Transforms all elements of the `Iterable` for as long as the specified function succeeds. | |
| * | |
| * **Example** (Filtering and transforming until failure) | |
| * | |
| * ```ts | |
| * import { Iterable, Result } from "effect" | |
| * | |
| * // Parse numbers until we hit an invalid one | |
| * const strings = ["1", "2", "3", "invalid", "4", "5"] | |
| * const numbers = Iterable.filterMapWhile(strings, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? Result.failVoid : Result.succeed(num) | |
| * }) | |
| * console.log(Array.from(numbers)) // [1, 2, 3] (stops at "invalid") | |
| * | |
| * // Take elements while they meet a condition and transform them | |
| * const values = [2, 4, 6, 7, 8, 10] | |
| * const doubledEvens = Iterable.filterMapWhile( | |
| * values, | |
| * (n) => n % 2 === 0 ? Result.succeed(n * 2) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(doubledEvens)) // [4, 8, 12] (stops at 7) | |
| * | |
| * // Process with index until condition fails | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const indexedUntilC = Iterable.filterMapWhile( | |
| * letters, | |
| * (letter, i) => letter !== "c" ? Result.succeed(`${i}: ${letter}`) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(indexedUntilC)) // ["0: a", "1: b"] (stops at "c") | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A, B, X>(f: (input: A, i: number) => Result<B, X>): (self: Iterable<A>) => Iterable<B> | |
| /** | |
| * Transforms all elements of the `Iterable` for as long as the specified function succeeds. | |
| * | |
| * **Example** (Filtering and transforming until failure) | |
| * | |
| * ```ts | |
| * import { Iterable, Result } from "effect" | |
| * | |
| * // Parse numbers until we hit an invalid one | |
| * const strings = ["1", "2", "3", "invalid", "4", "5"] | |
| * const numbers = Iterable.filterMapWhile(strings, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? Result.failVoid : Result.succeed(num) | |
| * }) | |
| * console.log(Array.from(numbers)) // [1, 2, 3] (stops at "invalid") | |
| * | |
| * // Take elements while they meet a condition and transform them | |
| * const values = [2, 4, 6, 7, 8, 10] | |
| * const doubledEvens = Iterable.filterMapWhile( | |
| * values, | |
| * (n) => n % 2 === 0 ? Result.succeed(n * 2) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(doubledEvens)) // [4, 8, 12] (stops at 7) | |
| * | |
| * // Process with index until condition fails | |
| * const letters = ["a", "b", "c", "d", "e"] | |
| * const indexedUntilC = Iterable.filterMapWhile( | |
| * letters, | |
| * (letter, i) => letter !== "c" ? Result.succeed(`${i}: ${letter}`) : Result.failVoid | |
| * ) | |
| * console.log(Array.from(indexedUntilC)) // ["0: a", "1: b"] (stops at "c") | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A, B, X>(self: Iterable<A>, f: (input: A, i: number) => Result<B, X>): Iterable<B> | |
| } = dual(2, <A, B, X>(self: Iterable<A>, f: (input: A, i: number) => Result<B, X>) => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let i = 0 | |
| return { | |
| next() { | |
| const result = iterator.next() | |
| if (result.done) { | |
| return { done: true, value: undefined } | |
| } | |
| const next = f(result.value, i++) | |
| if (R.isSuccess(next)) { | |
| return { done: false, value: next.success } | |
| } | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| } | |
| })) | |
| /** | |
| * Retrieves the `Some` values from an `Iterable` of `Option`s. | |
| * | |
| * **Example** (Extracting Some values) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual( | |
| * Array.from( | |
| * Iterable.getSomes([Option.some(1), Option.none(), Option.some(2)]) | |
| * ), | |
| * [1, 2] | |
| * ) | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| export const getSomes = <A>(self: Iterable<Option<A>>): Iterable<A> => { | |
| return { | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| return { | |
| next() { | |
| let result = iterator.next() | |
| while (!result.done) { | |
| if (O.isSome(result.value)) { | |
| return { done: false, value: result.value.value } | |
| } | |
| result = iterator.next() | |
| } | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * Returns a lazy iterable containing the failure values from an iterable of | |
| * `Result`s, skipping successful results. | |
| * | |
| * **Example** (Extracting failures) | |
| * | |
| * ```ts | |
| * import { Iterable, Result } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual( | |
| * Array.from( | |
| * Iterable.getFailures([ | |
| * Result.succeed(1), | |
| * Result.fail("err"), | |
| * Result.succeed(2) | |
| * ]) | |
| * ), | |
| * ["err"] | |
| * ) | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 4.0.0 | |
| */ | |
| export const getFailures = <R0, L>(self: Iterable<Result<R0, L>>): Iterable<L> => { | |
| return { | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| return { | |
| next() { | |
| let result = iterator.next() | |
| while (!result.done) { | |
| if (R.isFailure(result.value)) { | |
| return { done: false, value: result.value.failure } | |
| } | |
| result = iterator.next() | |
| } | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * Returns a lazy iterable containing the success values from an iterable of | |
| * `Result`s, skipping failed results. | |
| * | |
| * **Example** (Extracting successes) | |
| * | |
| * ```ts | |
| * import { Iterable, Result } from "effect" | |
| * import * as assert from "node:assert" | |
| * | |
| * assert.deepStrictEqual( | |
| * Array.from( | |
| * Iterable.getSuccesses([ | |
| * Result.succeed(1), | |
| * Result.fail("err"), | |
| * Result.succeed(2) | |
| * ]) | |
| * ), | |
| * [1, 2] | |
| * ) | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 4.0.0 | |
| */ | |
| export const getSuccesses = <R0, L>(self: Iterable<Result<R0, L>>): Iterable<R0> => { | |
| return { | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| return { | |
| next() { | |
| let result = iterator.next() | |
| while (!result.done) { | |
| if (R.isSuccess(result.value)) { | |
| return { done: false, value: result.value.success } | |
| } | |
| result = iterator.next() | |
| } | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * Filters an iterable to only include elements that match a predicate. | |
| * | |
| * **Details** | |
| * | |
| * This function creates a new iterable containing only the elements for which | |
| * the predicate function returns true. Like map, this operation is lazy and | |
| * elements are only tested when the iterable is consumed. | |
| * | |
| * **Example** (Filtering elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Filter even numbers | |
| * const numbers = [1, 2, 3, 4, 5, 6] | |
| * const evens = Iterable.filter(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evens)) // [2, 4, 6] | |
| * | |
| * // Filter with index | |
| * const items = ["a", "b", "c", "d"] | |
| * const oddPositions = Iterable.filter(items, (_, i) => i % 2 === 1) | |
| * console.log(Array.from(oddPositions)) // ["b", "d"] | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = ["hello", 42, "world", 100] | |
| * const onlyStrings = Iterable.filter( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(onlyStrings)) // ["hello", "world"] (typed as string[]) | |
| * | |
| * // Combine with map | |
| * const processed = Iterable.map( | |
| * Iterable.filter([1, 2, 3, 4, 5], (x) => x > 2), | |
| * (x) => x * 10 | |
| * ) | |
| * console.log(Array.from(processed)) // [30, 40, 50] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| export const filter: { | |
| /** | |
| * Filters an iterable to only include elements that match a predicate. | |
| * | |
| * **Details** | |
| * | |
| * This function creates a new iterable containing only the elements for which | |
| * the predicate function returns true. Like map, this operation is lazy and | |
| * elements are only tested when the iterable is consumed. | |
| * | |
| * **Example** (Filtering elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Filter even numbers | |
| * const numbers = [1, 2, 3, 4, 5, 6] | |
| * const evens = Iterable.filter(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evens)) // [2, 4, 6] | |
| * | |
| * // Filter with index | |
| * const items = ["a", "b", "c", "d"] | |
| * const oddPositions = Iterable.filter(items, (_, i) => i % 2 === 1) | |
| * console.log(Array.from(oddPositions)) // ["b", "d"] | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = ["hello", 42, "world", 100] | |
| * const onlyStrings = Iterable.filter( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(onlyStrings)) // ["hello", "world"] (typed as string[]) | |
| * | |
| * // Combine with map | |
| * const processed = Iterable.map( | |
| * Iterable.filter([1, 2, 3, 4, 5], (x) => x > 2), | |
| * (x) => x * 10 | |
| * ) | |
| * console.log(Array.from(processed)) // [30, 40, 50] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Iterable<B> | |
| /** | |
| * Filters an iterable to only include elements that match a predicate. | |
| * | |
| * **Details** | |
| * | |
| * This function creates a new iterable containing only the elements for which | |
| * the predicate function returns true. Like map, this operation is lazy and | |
| * elements are only tested when the iterable is consumed. | |
| * | |
| * **Example** (Filtering elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Filter even numbers | |
| * const numbers = [1, 2, 3, 4, 5, 6] | |
| * const evens = Iterable.filter(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evens)) // [2, 4, 6] | |
| * | |
| * // Filter with index | |
| * const items = ["a", "b", "c", "d"] | |
| * const oddPositions = Iterable.filter(items, (_, i) => i % 2 === 1) | |
| * console.log(Array.from(oddPositions)) // ["b", "d"] | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = ["hello", 42, "world", 100] | |
| * const onlyStrings = Iterable.filter( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(onlyStrings)) // ["hello", "world"] (typed as string[]) | |
| * | |
| * // Combine with map | |
| * const processed = Iterable.map( | |
| * Iterable.filter([1, 2, 3, 4, 5], (x) => x > 2), | |
| * (x) => x * 10 | |
| * ) | |
| * console.log(Array.from(processed)) // [30, 40, 50] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Iterable<A> | |
| /** | |
| * Filters an iterable to only include elements that match a predicate. | |
| * | |
| * **Details** | |
| * | |
| * This function creates a new iterable containing only the elements for which | |
| * the predicate function returns true. Like map, this operation is lazy and | |
| * elements are only tested when the iterable is consumed. | |
| * | |
| * **Example** (Filtering elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Filter even numbers | |
| * const numbers = [1, 2, 3, 4, 5, 6] | |
| * const evens = Iterable.filter(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evens)) // [2, 4, 6] | |
| * | |
| * // Filter with index | |
| * const items = ["a", "b", "c", "d"] | |
| * const oddPositions = Iterable.filter(items, (_, i) => i % 2 === 1) | |
| * console.log(Array.from(oddPositions)) // ["b", "d"] | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = ["hello", 42, "world", 100] | |
| * const onlyStrings = Iterable.filter( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(onlyStrings)) // ["hello", "world"] (typed as string[]) | |
| * | |
| * // Combine with map | |
| * const processed = Iterable.map( | |
| * Iterable.filter([1, 2, 3, 4, 5], (x) => x > 2), | |
| * (x) => x * 10 | |
| * ) | |
| * console.log(Array.from(processed)) // [30, 40, 50] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Iterable<B> | |
| /** | |
| * Filters an iterable to only include elements that match a predicate. | |
| * | |
| * **Details** | |
| * | |
| * This function creates a new iterable containing only the elements for which | |
| * the predicate function returns true. Like map, this operation is lazy and | |
| * elements are only tested when the iterable is consumed. | |
| * | |
| * **Example** (Filtering elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Filter even numbers | |
| * const numbers = [1, 2, 3, 4, 5, 6] | |
| * const evens = Iterable.filter(numbers, (x) => x % 2 === 0) | |
| * console.log(Array.from(evens)) // [2, 4, 6] | |
| * | |
| * // Filter with index | |
| * const items = ["a", "b", "c", "d"] | |
| * const oddPositions = Iterable.filter(items, (_, i) => i % 2 === 1) | |
| * console.log(Array.from(oddPositions)) // ["b", "d"] | |
| * | |
| * // Type refinement | |
| * const mixed: Array<string | number> = ["hello", 42, "world", 100] | |
| * const onlyStrings = Iterable.filter( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(Array.from(onlyStrings)) // ["hello", "world"] (typed as string[]) | |
| * | |
| * // Combine with map | |
| * const processed = Iterable.map( | |
| * Iterable.filter([1, 2, 3, 4, 5], (x) => x > 2), | |
| * (x) => x * 10 | |
| * ) | |
| * console.log(Array.from(processed)) // [30, 40, 50] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Iterable<A> | |
| } = dual( | |
| 2, | |
| <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Iterable<A> => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let i = 0 | |
| return { | |
| next() { | |
| let result = iterator.next() | |
| while (!result.done) { | |
| if (predicate(result.value, i++)) { | |
| return { done: false, value: result.value } | |
| } | |
| result = iterator.next() | |
| } | |
| return { done: true, value: undefined } | |
| } | |
| } | |
| } | |
| }) | |
| ) | |
| /** | |
| * Transforms elements using a function that may return null or undefined, filtering out the null/undefined results. | |
| * | |
| * **When to use** | |
| * | |
| * Use when working with APIs or functions that return nullable values, | |
| * providing a clean way to filter out null or undefined while transforming. | |
| * | |
| * **Example** (FlatMapping nullable results) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Extract valid elements from nullable function results | |
| * const data = ["1", "2", "invalid", "4"] | |
| * const parsed = Iterable.flatMapNullishOr(data, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? null : num * 2 | |
| * }) | |
| * console.log(Array.from(parsed)) // [2, 4, 8] | |
| * | |
| * // Safe property access | |
| * const objects = [ | |
| * { nested: { value: 10 } }, | |
| * { nested: null }, | |
| * { nested: { value: 20 } }, | |
| * {} | |
| * ] | |
| * const values = Iterable.flatMapNullishOr(objects, (obj) => obj.nested?.value) | |
| * console.log(Array.from(values)) // [10, 20] | |
| * | |
| * // Working with Map.get (returns undefined for missing keys) | |
| * const map = new Map([ | |
| * ["a", 1], | |
| * ["b", 2], | |
| * ["c", 3] | |
| * ]) | |
| * const keys = ["a", "x", "b", "y", "c"] | |
| * const foundValues = Iterable.flatMapNullishOr(keys, (key) => map.get(key)) | |
| * console.log(Array.from(foundValues)) // [1, 2, 3] | |
| * ``` | |
| * | |
| * @category sequencing | |
| * @since 4.0.0 | |
| */ | |
| export const flatMapNullishOr: { | |
| /** | |
| * Transforms elements using a function that may return null or undefined, filtering out the null/undefined results. | |
| * | |
| * **When to use** | |
| * | |
| * Use when working with APIs or functions that return nullable values, | |
| * providing a clean way to filter out null or undefined while transforming. | |
| * | |
| * **Example** (FlatMapping nullable results) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Extract valid elements from nullable function results | |
| * const data = ["1", "2", "invalid", "4"] | |
| * const parsed = Iterable.flatMapNullishOr(data, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? null : num * 2 | |
| * }) | |
| * console.log(Array.from(parsed)) // [2, 4, 8] | |
| * | |
| * // Safe property access | |
| * const objects = [ | |
| * { nested: { value: 10 } }, | |
| * { nested: null }, | |
| * { nested: { value: 20 } }, | |
| * {} | |
| * ] | |
| * const values = Iterable.flatMapNullishOr(objects, (obj) => obj.nested?.value) | |
| * console.log(Array.from(values)) // [10, 20] | |
| * | |
| * // Working with Map.get (returns undefined for missing keys) | |
| * const map = new Map([ | |
| * ["a", 1], | |
| * ["b", 2], | |
| * ["c", 3] | |
| * ]) | |
| * const keys = ["a", "x", "b", "y", "c"] | |
| * const foundValues = Iterable.flatMapNullishOr(keys, (key) => map.get(key)) | |
| * console.log(Array.from(foundValues)) // [1, 2, 3] | |
| * ``` | |
| * | |
| * @category sequencing | |
| * @since 4.0.0 | |
| */ | |
| <A, B>(f: (a: A) => B): (self: Iterable<A>) => Iterable<NonNullable<B>> | |
| /** | |
| * Transforms elements using a function that may return null or undefined, filtering out the null/undefined results. | |
| * | |
| * **When to use** | |
| * | |
| * Use when working with APIs or functions that return nullable values, | |
| * providing a clean way to filter out null or undefined while transforming. | |
| * | |
| * **Example** (FlatMapping nullable results) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Extract valid elements from nullable function results | |
| * const data = ["1", "2", "invalid", "4"] | |
| * const parsed = Iterable.flatMapNullishOr(data, (s) => { | |
| * const num = parseInt(s) | |
| * return isNaN(num) ? null : num * 2 | |
| * }) | |
| * console.log(Array.from(parsed)) // [2, 4, 8] | |
| * | |
| * // Safe property access | |
| * const objects = [ | |
| * { nested: { value: 10 } }, | |
| * { nested: null }, | |
| * { nested: { value: 20 } }, | |
| * {} | |
| * ] | |
| * const values = Iterable.flatMapNullishOr(objects, (obj) => obj.nested?.value) | |
| * console.log(Array.from(values)) // [10, 20] | |
| * | |
| * // Working with Map.get (returns undefined for missing keys) | |
| * const map = new Map([ | |
| * ["a", 1], | |
| * ["b", 2], | |
| * ["c", 3] | |
| * ]) | |
| * const keys = ["a", "x", "b", "y", "c"] | |
| * const foundValues = Iterable.flatMapNullishOr(keys, (key) => map.get(key)) | |
| * console.log(Array.from(foundValues)) // [1, 2, 3] | |
| * ``` | |
| * | |
| * @category sequencing | |
| * @since 4.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, f: (a: A) => B): Iterable<NonNullable<B>> | |
| } = dual( | |
| 2, | |
| <A, B>(self: Iterable<A>, f: (a: A) => B): Iterable<NonNullable<B>> => | |
| filterMap(self, (a) => { | |
| const b = f(a) | |
| return b == null ? R.failVoid : R.succeed(b) | |
| }) | |
| ) | |
| /** | |
| * Checks whether a predicate holds true for some `Iterable` element. | |
| * | |
| * **Example** (Checking whether some element matches) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 5, 7, 8] | |
| * const hasEven = Iterable.some(numbers, (x) => x % 2 === 0) | |
| * console.log(hasEven) // true (because of 8) | |
| * | |
| * const allOdd = [1, 3, 5, 7] | |
| * const hasEvenInAllOdd = Iterable.some(allOdd, (x) => x % 2 === 0) | |
| * console.log(hasEvenInAllOdd) // false | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c"] | |
| * const hasElementAtIndex2 = Iterable.some(letters, (_, i) => i === 2) | |
| * console.log(hasElementAtIndex2) // true | |
| * | |
| * // Early termination - stops at first match | |
| * const infiniteOdds = Iterable.filter(Iterable.range(1), (x) => x % 2 === 1) | |
| * const hasEvenInInfiniteOdds = Iterable.some( | |
| * Iterable.take(infiniteOdds, 1000), | |
| * (x) => x % 2 === 0 | |
| * ) | |
| * console.log(hasEvenInInfiniteOdds) // false (quickly, doesn't check all 1000) | |
| * | |
| * // Type guard usage | |
| * const mixed: Array<string | number> = [1, 2, "hello"] | |
| * const hasString = Iterable.some( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(hasString) // true | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| export const some: { | |
| /** | |
| * Checks whether a predicate holds true for some `Iterable` element. | |
| * | |
| * **Example** (Checking whether some element matches) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 5, 7, 8] | |
| * const hasEven = Iterable.some(numbers, (x) => x % 2 === 0) | |
| * console.log(hasEven) // true (because of 8) | |
| * | |
| * const allOdd = [1, 3, 5, 7] | |
| * const hasEvenInAllOdd = Iterable.some(allOdd, (x) => x % 2 === 0) | |
| * console.log(hasEvenInAllOdd) // false | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c"] | |
| * const hasElementAtIndex2 = Iterable.some(letters, (_, i) => i === 2) | |
| * console.log(hasElementAtIndex2) // true | |
| * | |
| * // Early termination - stops at first match | |
| * const infiniteOdds = Iterable.filter(Iterable.range(1), (x) => x % 2 === 1) | |
| * const hasEvenInInfiniteOdds = Iterable.some( | |
| * Iterable.take(infiniteOdds, 1000), | |
| * (x) => x % 2 === 0 | |
| * ) | |
| * console.log(hasEvenInInfiniteOdds) // false (quickly, doesn't check all 1000) | |
| * | |
| * // Type guard usage | |
| * const mixed: Array<string | number> = [1, 2, "hello"] | |
| * const hasString = Iterable.some( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(hasString) // true | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(predicate: (a: A, i: number) => boolean): (self: Iterable<A>) => boolean | |
| /** | |
| * Checks whether a predicate holds true for some `Iterable` element. | |
| * | |
| * **Example** (Checking whether some element matches) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const numbers = [1, 3, 5, 7, 8] | |
| * const hasEven = Iterable.some(numbers, (x) => x % 2 === 0) | |
| * console.log(hasEven) // true (because of 8) | |
| * | |
| * const allOdd = [1, 3, 5, 7] | |
| * const hasEvenInAllOdd = Iterable.some(allOdd, (x) => x % 2 === 0) | |
| * console.log(hasEvenInAllOdd) // false | |
| * | |
| * // With index | |
| * const letters = ["a", "b", "c"] | |
| * const hasElementAtIndex2 = Iterable.some(letters, (_, i) => i === 2) | |
| * console.log(hasElementAtIndex2) // true | |
| * | |
| * // Early termination - stops at first match | |
| * const infiniteOdds = Iterable.filter(Iterable.range(1), (x) => x % 2 === 1) | |
| * const hasEvenInInfiniteOdds = Iterable.some( | |
| * Iterable.take(infiniteOdds, 1000), | |
| * (x) => x % 2 === 0 | |
| * ) | |
| * console.log(hasEvenInInfiniteOdds) // false (quickly, doesn't check all 1000) | |
| * | |
| * // Type guard usage | |
| * const mixed: Array<string | number> = [1, 2, "hello"] | |
| * const hasString = Iterable.some( | |
| * mixed, | |
| * (x): x is string => typeof x === "string" | |
| * ) | |
| * console.log(hasString) // true | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): boolean | |
| } = dual( | |
| 2, | |
| <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): boolean => { | |
| let i = 0 | |
| for (const a of self) { | |
| if (predicate(a, i++)) { | |
| return true | |
| } | |
| } | |
| return false | |
| } | |
| ) | |
| /** | |
| * Generates an iterable by repeatedly applying a function that produces the | |
| * next element and state. | |
| * | |
| * **Details** | |
| * | |
| * This is useful for creating iterables from a generating function that | |
| * maintains state. The function should return `Option.some([value, nextState])` | |
| * to continue or `Option.none()` to stop. | |
| * | |
| * **Example** (Unfolding state into values) | |
| * | |
| * ```ts | |
| * import { Iterable, Option } from "effect" | |
| * | |
| * // Generate Fibonacci sequence | |
| * const fibonacci = Iterable.unfold([0, 1], ([a, b]) => Option.some([a, [b, a + b]])) | |
| * const first10Fib = Iterable.take(fibonacci, 10) | |
| * console.log(Array.from(first10Fib)) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] | |
| * | |
| * // Generate powers of 2 up to a limit | |
| * const powersOf2 = Iterable.unfold(1, (n) => n <= 1000 ? Option.some([n, n * 2]) : Option.none()) | |
| * console.log(Array.from(powersOf2)) // [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] | |
| * | |
| * // Generate countdown | |
| * const countdown = Iterable.unfold(5, (n) => n > 0 ? Option.some([n, n - 1]) : Option.none()) | |
| * console.log(Array.from(countdown)) // [5, 4, 3, 2, 1] | |
| * | |
| * // Generate collatz sequence | |
| * const collatz = Iterable.unfold(7, (n) => { | |
| * if (n === 1) return Option.none() | |
| * const next = n % 2 === 0 ? n / 2 : n * 3 + 1 | |
| * return Option.some([n, next]) | |
| * }) | |
| * console.log(Array.from(collatz)) // [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2] | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| export const unfold = <B, A>(b: B, f: (b: B) => Option<readonly [A, B]>): Iterable<A> => ({ | |
| [Symbol.iterator]() { | |
| let next = b | |
| return { | |
| next() { | |
| const ab = f(next) | |
| if (O.isNone(ab)) { | |
| return { done: true, value: undefined } | |
| } | |
| const [a, b] = ab.value | |
| next = b | |
| return { done: false, value: a } | |
| } | |
| } | |
| } | |
| }) | |
| /** | |
| * Iterates over the `Iterable`, applying `f` to each element. | |
| * | |
| * **Example** (Iterating with side effects) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Print each element | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * Iterable.forEach(numbers, (n) => console.log(n)) | |
| * // Prints: 1, 2, 3, 4, 5 | |
| * | |
| * // Use index in the callback | |
| * const letters = ["a", "b", "c"] | |
| * Iterable.forEach(letters, (letter, i) => { | |
| * console.log(`${i}: ${letter}`) | |
| * }) | |
| * // Prints: "0: a", "1: b", "2: c" | |
| * | |
| * // Side effects with any iterable | |
| * const results: Array<number> = [] | |
| * Iterable.forEach(Iterable.range(1, 5), (n) => { | |
| * results.push(n * n) | |
| * }) | |
| * console.log(results) // [1, 4, 9, 16, 25] | |
| * | |
| * // Process in chunks | |
| * const data = Iterable.chunksOf([1, 2, 3, 4, 5, 6], 2) | |
| * Iterable.forEach(data, (chunk) => { | |
| * console.log(`Processing chunk: ${Array.from(chunk)}`) | |
| * }) | |
| * // Prints: "Processing chunk: 1,2", "Processing chunk: 3,4", "Processing chunk: 5,6" | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| export const forEach: { | |
| /** | |
| * Iterates over the `Iterable`, applying `f` to each element. | |
| * | |
| * **Example** (Iterating with side effects) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Print each element | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * Iterable.forEach(numbers, (n) => console.log(n)) | |
| * // Prints: 1, 2, 3, 4, 5 | |
| * | |
| * // Use index in the callback | |
| * const letters = ["a", "b", "c"] | |
| * Iterable.forEach(letters, (letter, i) => { | |
| * console.log(`${i}: ${letter}`) | |
| * }) | |
| * // Prints: "0: a", "1: b", "2: c" | |
| * | |
| * // Side effects with any iterable | |
| * const results: Array<number> = [] | |
| * Iterable.forEach(Iterable.range(1, 5), (n) => { | |
| * results.push(n * n) | |
| * }) | |
| * console.log(results) // [1, 4, 9, 16, 25] | |
| * | |
| * // Process in chunks | |
| * const data = Iterable.chunksOf([1, 2, 3, 4, 5, 6], 2) | |
| * Iterable.forEach(data, (chunk) => { | |
| * console.log(`Processing chunk: ${Array.from(chunk)}`) | |
| * }) | |
| * // Prints: "Processing chunk: 1,2", "Processing chunk: 3,4", "Processing chunk: 5,6" | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(f: (a: A, i: number) => void): (self: Iterable<A>) => void | |
| /** | |
| * Iterates over the `Iterable`, applying `f` to each element. | |
| * | |
| * **Example** (Iterating with side effects) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Print each element | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * Iterable.forEach(numbers, (n) => console.log(n)) | |
| * // Prints: 1, 2, 3, 4, 5 | |
| * | |
| * // Use index in the callback | |
| * const letters = ["a", "b", "c"] | |
| * Iterable.forEach(letters, (letter, i) => { | |
| * console.log(`${i}: ${letter}`) | |
| * }) | |
| * // Prints: "0: a", "1: b", "2: c" | |
| * | |
| * // Side effects with any iterable | |
| * const results: Array<number> = [] | |
| * Iterable.forEach(Iterable.range(1, 5), (n) => { | |
| * results.push(n * n) | |
| * }) | |
| * console.log(results) // [1, 4, 9, 16, 25] | |
| * | |
| * // Process in chunks | |
| * const data = Iterable.chunksOf([1, 2, 3, 4, 5, 6], 2) | |
| * Iterable.forEach(data, (chunk) => { | |
| * console.log(`Processing chunk: ${Array.from(chunk)}`) | |
| * }) | |
| * // Prints: "Processing chunk: 1,2", "Processing chunk: 3,4", "Processing chunk: 5,6" | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, f: (a: A, i: number) => void): void | |
| } = dual(2, <A>(self: Iterable<A>, f: (a: A, i: number) => void): void => { | |
| let i = 0 | |
| for (const a of self) { | |
| f(a, i++) | |
| } | |
| }) | |
| /** | |
| * Reduces an iterable to a single value by applying a function to each element and accumulating the result. | |
| * | |
| * **Details** | |
| * | |
| * This function applies a reducing function against an accumulator and each element | |
| * of the iterable (from left to right) to reduce it to a single value. | |
| * | |
| * **Example** (Reducing an iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Sum all numbers | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const sum = Iterable.reduce(numbers, 0, (acc, n) => acc + n) | |
| * console.log(sum) // 15 | |
| * | |
| * // Find maximum value | |
| * const values = [3, 1, 4, 1, 5, 9, 2] | |
| * const max = Iterable.reduce(values, -Infinity, Math.max) | |
| * console.log(max) // 9 | |
| * | |
| * // Build an object from key-value pairs | |
| * const pairs = [["a", 1], ["b", 2], ["c", 3]] as const | |
| * const obj = Iterable.reduce( | |
| * pairs, | |
| * {} as Record<string, number>, | |
| * (acc, [key, value]) => { | |
| * acc[key] = value | |
| * return acc | |
| * } | |
| * ) | |
| * console.log(obj) // { a: 1, b: 2, c: 3 } | |
| * | |
| * // Use index in the reducer | |
| * const letters = ["a", "b", "c"] | |
| * const indexed = Iterable.reduce( | |
| * letters, | |
| * [] as Array<string>, | |
| * (acc, letter, i) => { | |
| * acc.push(`${i}: ${letter}`) | |
| * return acc | |
| * } | |
| * ) | |
| * console.log(indexed) // ["0: a", "1: b", "2: c"] | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 2.0.0 | |
| */ | |
| export const reduce: { | |
| /** | |
| * Reduces an iterable to a single value by applying a function to each element and accumulating the result. | |
| * | |
| * **Details** | |
| * | |
| * This function applies a reducing function against an accumulator and each element | |
| * of the iterable (from left to right) to reduce it to a single value. | |
| * | |
| * **Example** (Reducing an iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Sum all numbers | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const sum = Iterable.reduce(numbers, 0, (acc, n) => acc + n) | |
| * console.log(sum) // 15 | |
| * | |
| * // Find maximum value | |
| * const values = [3, 1, 4, 1, 5, 9, 2] | |
| * const max = Iterable.reduce(values, -Infinity, Math.max) | |
| * console.log(max) // 9 | |
| * | |
| * // Build an object from key-value pairs | |
| * const pairs = [["a", 1], ["b", 2], ["c", 3]] as const | |
| * const obj = Iterable.reduce( | |
| * pairs, | |
| * {} as Record<string, number>, | |
| * (acc, [key, value]) => { | |
| * acc[key] = value | |
| * return acc | |
| * } | |
| * ) | |
| * console.log(obj) // { a: 1, b: 2, c: 3 } | |
| * | |
| * // Use index in the reducer | |
| * const letters = ["a", "b", "c"] | |
| * const indexed = Iterable.reduce( | |
| * letters, | |
| * [] as Array<string>, | |
| * (acc, letter, i) => { | |
| * acc.push(`${i}: ${letter}`) | |
| * return acc | |
| * } | |
| * ) | |
| * console.log(indexed) // ["0: a", "1: b", "2: c"] | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 2.0.0 | |
| */ | |
| <B, A>(b: B, f: (b: B, a: A, i: number) => B): (self: Iterable<A>) => B | |
| /** | |
| * Reduces an iterable to a single value by applying a function to each element and accumulating the result. | |
| * | |
| * **Details** | |
| * | |
| * This function applies a reducing function against an accumulator and each element | |
| * of the iterable (from left to right) to reduce it to a single value. | |
| * | |
| * **Example** (Reducing an iterable) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Sum all numbers | |
| * const numbers = [1, 2, 3, 4, 5] | |
| * const sum = Iterable.reduce(numbers, 0, (acc, n) => acc + n) | |
| * console.log(sum) // 15 | |
| * | |
| * // Find maximum value | |
| * const values = [3, 1, 4, 1, 5, 9, 2] | |
| * const max = Iterable.reduce(values, -Infinity, Math.max) | |
| * console.log(max) // 9 | |
| * | |
| * // Build an object from key-value pairs | |
| * const pairs = [["a", 1], ["b", 2], ["c", 3]] as const | |
| * const obj = Iterable.reduce( | |
| * pairs, | |
| * {} as Record<string, number>, | |
| * (acc, [key, value]) => { | |
| * acc[key] = value | |
| * return acc | |
| * } | |
| * ) | |
| * console.log(obj) // { a: 1, b: 2, c: 3 } | |
| * | |
| * // Use index in the reducer | |
| * const letters = ["a", "b", "c"] | |
| * const indexed = Iterable.reduce( | |
| * letters, | |
| * [] as Array<string>, | |
| * (acc, letter, i) => { | |
| * acc.push(`${i}: ${letter}`) | |
| * return acc | |
| * } | |
| * ) | |
| * console.log(indexed) // ["0: a", "1: b", "2: c"] | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A, i: number) => B): B | |
| } = dual(3, <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A, i: number) => B): B => { | |
| if (Array.isArray(self)) { | |
| return self.reduce(f, b) | |
| } | |
| let i = 0 | |
| let result = b | |
| for (const n of self) { | |
| result = f(result, n, i++) | |
| } | |
| return result | |
| }) | |
| /** | |
| * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. | |
| * | |
| * **Example** (Deduplicating adjacent elements with custom equivalence) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Remove adjacent duplicates with custom equality | |
| * const numbers = [1, 1, 2, 2, 3, 1, 1] | |
| * const dedupedNumbers = Iterable.dedupeAdjacentWith(numbers, (a, b) => a === b) | |
| * console.log(Array.from(dedupedNumbers)) // [1, 2, 3, 1] | |
| * | |
| * // Case-insensitive deduplication | |
| * const words = ["Hello", "HELLO", "world", "World", "test"] | |
| * const caseInsensitive = (a: string, b: string) => | |
| * a.toLowerCase() === b.toLowerCase() | |
| * const dedupedWords = Iterable.dedupeAdjacentWith(words, caseInsensitive) | |
| * console.log(Array.from(dedupedWords)) // ["Hello", "world", "test"] | |
| * | |
| * // Deduplication by object property | |
| * const users = [ | |
| * { id: 1, name: "Alice" }, | |
| * { id: 1, name: "Alice Updated" }, // different name, same id | |
| * { id: 2, name: "Bob" }, | |
| * { id: 2, name: "Bob" }, | |
| * { id: 3, name: "Charlie" } | |
| * ] | |
| * const byId = (a: typeof users[0], b: typeof users[0]) => a.id === b.id | |
| * const dedupedUsers = Iterable.dedupeAdjacentWith(users, byId) | |
| * console.log(Array.from(dedupedUsers).map((u) => u.id)) // [1, 2, 3] | |
| * | |
| * // Approximate numeric equality | |
| * const floats = [1.0, 1.01, 1.02, 2.0, 2.01, 3.0] | |
| * const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.1 | |
| * const dedupedFloats = Iterable.dedupeAdjacentWith(floats, approxEqual) | |
| * console.log(Array.from(dedupedFloats)) // [1.0, 2.0, 3.0] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| export const dedupeAdjacentWith: { | |
| /** | |
| * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. | |
| * | |
| * **Example** (Deduplicating adjacent elements with custom equivalence) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Remove adjacent duplicates with custom equality | |
| * const numbers = [1, 1, 2, 2, 3, 1, 1] | |
| * const dedupedNumbers = Iterable.dedupeAdjacentWith(numbers, (a, b) => a === b) | |
| * console.log(Array.from(dedupedNumbers)) // [1, 2, 3, 1] | |
| * | |
| * // Case-insensitive deduplication | |
| * const words = ["Hello", "HELLO", "world", "World", "test"] | |
| * const caseInsensitive = (a: string, b: string) => | |
| * a.toLowerCase() === b.toLowerCase() | |
| * const dedupedWords = Iterable.dedupeAdjacentWith(words, caseInsensitive) | |
| * console.log(Array.from(dedupedWords)) // ["Hello", "world", "test"] | |
| * | |
| * // Deduplication by object property | |
| * const users = [ | |
| * { id: 1, name: "Alice" }, | |
| * { id: 1, name: "Alice Updated" }, // different name, same id | |
| * { id: 2, name: "Bob" }, | |
| * { id: 2, name: "Bob" }, | |
| * { id: 3, name: "Charlie" } | |
| * ] | |
| * const byId = (a: typeof users[0], b: typeof users[0]) => a.id === b.id | |
| * const dedupedUsers = Iterable.dedupeAdjacentWith(users, byId) | |
| * console.log(Array.from(dedupedUsers).map((u) => u.id)) // [1, 2, 3] | |
| * | |
| * // Approximate numeric equality | |
| * const floats = [1.0, 1.01, 1.02, 2.0, 2.01, 3.0] | |
| * const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.1 | |
| * const dedupedFloats = Iterable.dedupeAdjacentWith(floats, approxEqual) | |
| * console.log(Array.from(dedupedFloats)) // [1.0, 2.0, 3.0] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A>(isEquivalent: (self: A, that: A) => boolean): (self: Iterable<A>) => Iterable<A> | |
| /** | |
| * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. | |
| * | |
| * **Example** (Deduplicating adjacent elements with custom equivalence) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Remove adjacent duplicates with custom equality | |
| * const numbers = [1, 1, 2, 2, 3, 1, 1] | |
| * const dedupedNumbers = Iterable.dedupeAdjacentWith(numbers, (a, b) => a === b) | |
| * console.log(Array.from(dedupedNumbers)) // [1, 2, 3, 1] | |
| * | |
| * // Case-insensitive deduplication | |
| * const words = ["Hello", "HELLO", "world", "World", "test"] | |
| * const caseInsensitive = (a: string, b: string) => | |
| * a.toLowerCase() === b.toLowerCase() | |
| * const dedupedWords = Iterable.dedupeAdjacentWith(words, caseInsensitive) | |
| * console.log(Array.from(dedupedWords)) // ["Hello", "world", "test"] | |
| * | |
| * // Deduplication by object property | |
| * const users = [ | |
| * { id: 1, name: "Alice" }, | |
| * { id: 1, name: "Alice Updated" }, // different name, same id | |
| * { id: 2, name: "Bob" }, | |
| * { id: 2, name: "Bob" }, | |
| * { id: 3, name: "Charlie" } | |
| * ] | |
| * const byId = (a: typeof users[0], b: typeof users[0]) => a.id === b.id | |
| * const dedupedUsers = Iterable.dedupeAdjacentWith(users, byId) | |
| * console.log(Array.from(dedupedUsers).map((u) => u.id)) // [1, 2, 3] | |
| * | |
| * // Approximate numeric equality | |
| * const floats = [1.0, 1.01, 1.02, 2.0, 2.01, 3.0] | |
| * const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.1 | |
| * const dedupedFloats = Iterable.dedupeAdjacentWith(floats, approxEqual) | |
| * console.log(Array.from(dedupedFloats)) // [1.0, 2.0, 3.0] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A> | |
| } = dual(2, <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A> => ({ | |
| [Symbol.iterator]() { | |
| const iterator = self[Symbol.iterator]() | |
| let first = true | |
| let last: A | |
| function next(): IteratorResult<A> { | |
| const result = iterator.next() | |
| if (result.done) { | |
| return { done: true, value: undefined } | |
| } | |
| if (first) { | |
| first = false | |
| last = result.value | |
| return result | |
| } | |
| const current = result.value | |
| if (isEquivalent(last, current)) { | |
| return next() | |
| } | |
| last = current | |
| return result | |
| } | |
| return { next } | |
| } | |
| })) | |
| /** | |
| * Deduplicates adjacent elements that are identical. | |
| * | |
| * **Example** (Deduplicating adjacent elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Remove adjacent duplicate numbers | |
| * const numbers = [1, 1, 2, 2, 2, 3, 1, 1] | |
| * const deduped = Iterable.dedupeAdjacent(numbers) | |
| * console.log(Array.from(deduped)) // [1, 2, 3, 1] | |
| * | |
| * // Remove adjacent duplicate characters | |
| * const letters = "aabbccaa" | |
| * const dedupedLetters = Iterable.dedupeAdjacent(letters) | |
| * console.log(Array.from(dedupedLetters)) // ["a", "b", "c", "a"] | |
| * | |
| * // Works with objects using deep equality | |
| * const objects = [ | |
| * { type: "A" }, | |
| * { type: "A" }, | |
| * { type: "B" }, | |
| * { type: "B" }, | |
| * { type: "A" } | |
| * ] | |
| * const dedupedObjects = Iterable.dedupeAdjacent(objects) | |
| * console.log(Array.from(dedupedObjects).map((o) => o.type)) // ["A", "B", "A"] | |
| * | |
| * // Clean up streaming data | |
| * const sensorData = [100, 100, 100, 101, 101, 102, 102, 102, 100] | |
| * const cleanedData = Iterable.dedupeAdjacent(sensorData) | |
| * console.log(Array.from(cleanedData)) // [100, 101, 102, 100] | |
| * ``` | |
| * | |
| * @category filtering | |
| * @since 2.0.0 | |
| */ | |
| export const dedupeAdjacent: <A>(self: Iterable<A>) => Iterable<A> = dedupeAdjacentWith(Equal.asEquivalence()) | |
| /** | |
| * Zips this Iterable crosswise with the specified Iterable using the specified combiner. | |
| * | |
| * **Example** (Combining cartesian products) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Create coordinate pairs | |
| * const xs = [1, 2] | |
| * const ys = ["a", "b", "c"] | |
| * const coordinates = Iterable.cartesianWith(xs, ys, (x, y) => `(${x},${y})`) | |
| * console.log(Array.from(coordinates)) // ["(1,a)", "(1,b)", "(1,c)", "(2,a)", "(2,b)", "(2,c)"] | |
| * | |
| * // Generate all combinations of options | |
| * const sizes = ["S", "M", "L"] | |
| * const colors = ["red", "blue"] | |
| * const products = Iterable.cartesianWith( | |
| * sizes, | |
| * colors, | |
| * (size, color) => ({ size, color }) | |
| * ) | |
| * console.log(Array.from(products)) | |
| * // [ | |
| * // { size: "S", color: "red" }, { size: "S", color: "blue" }, | |
| * // { size: "M", color: "red" }, { size: "M", color: "blue" }, | |
| * // { size: "L", color: "red" }, { size: "L", color: "blue" } | |
| * // ] | |
| * | |
| * // Mathematical operations on all pairs | |
| * const a = [1, 2, 3] | |
| * const b = [10, 20] | |
| * const mathProducts = Iterable.cartesianWith(a, b, (x, y) => x * y) | |
| * console.log(Array.from(mathProducts)) // [10, 20, 20, 40, 30, 60] | |
| * | |
| * // Create test data combinations | |
| * const userTypes = ["admin", "user"] | |
| * const features = ["read", "write", "delete"] | |
| * const testCases = Iterable.cartesianWith( | |
| * userTypes, | |
| * features, | |
| * (user, feature) => `${user}_can_${feature}` | |
| * ) | |
| * console.log(Array.from(testCases)) | |
| * // ["admin_can_read", "admin_can_write", "admin_can_delete", "user_can_read", "user_can_write", "user_can_delete"] | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| export const cartesianWith: { | |
| /** | |
| * Zips this Iterable crosswise with the specified Iterable using the specified combiner. | |
| * | |
| * **Example** (Combining cartesian products) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Create coordinate pairs | |
| * const xs = [1, 2] | |
| * const ys = ["a", "b", "c"] | |
| * const coordinates = Iterable.cartesianWith(xs, ys, (x, y) => `(${x},${y})`) | |
| * console.log(Array.from(coordinates)) // ["(1,a)", "(1,b)", "(1,c)", "(2,a)", "(2,b)", "(2,c)"] | |
| * | |
| * // Generate all combinations of options | |
| * const sizes = ["S", "M", "L"] | |
| * const colors = ["red", "blue"] | |
| * const products = Iterable.cartesianWith( | |
| * sizes, | |
| * colors, | |
| * (size, color) => ({ size, color }) | |
| * ) | |
| * console.log(Array.from(products)) | |
| * // [ | |
| * // { size: "S", color: "red" }, { size: "S", color: "blue" }, | |
| * // { size: "M", color: "red" }, { size: "M", color: "blue" }, | |
| * // { size: "L", color: "red" }, { size: "L", color: "blue" } | |
| * // ] | |
| * | |
| * // Mathematical operations on all pairs | |
| * const a = [1, 2, 3] | |
| * const b = [10, 20] | |
| * const mathProducts = Iterable.cartesianWith(a, b, (x, y) => x * y) | |
| * console.log(Array.from(mathProducts)) // [10, 20, 20, 40, 30, 60] | |
| * | |
| * // Create test data combinations | |
| * const userTypes = ["admin", "user"] | |
| * const features = ["read", "write", "delete"] | |
| * const testCases = Iterable.cartesianWith( | |
| * userTypes, | |
| * features, | |
| * (user, feature) => `${user}_can_${feature}` | |
| * ) | |
| * console.log(Array.from(testCases)) | |
| * // ["admin_can_read", "admin_can_write", "admin_can_delete", "user_can_read", "user_can_write", "user_can_delete"] | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B, C>(that: Iterable<B>, f: (a: A, b: B) => C): (self: Iterable<A>) => Iterable<C> | |
| /** | |
| * Zips this Iterable crosswise with the specified Iterable using the specified combiner. | |
| * | |
| * **Example** (Combining cartesian products) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // Create coordinate pairs | |
| * const xs = [1, 2] | |
| * const ys = ["a", "b", "c"] | |
| * const coordinates = Iterable.cartesianWith(xs, ys, (x, y) => `(${x},${y})`) | |
| * console.log(Array.from(coordinates)) // ["(1,a)", "(1,b)", "(1,c)", "(2,a)", "(2,b)", "(2,c)"] | |
| * | |
| * // Generate all combinations of options | |
| * const sizes = ["S", "M", "L"] | |
| * const colors = ["red", "blue"] | |
| * const products = Iterable.cartesianWith( | |
| * sizes, | |
| * colors, | |
| * (size, color) => ({ size, color }) | |
| * ) | |
| * console.log(Array.from(products)) | |
| * // [ | |
| * // { size: "S", color: "red" }, { size: "S", color: "blue" }, | |
| * // { size: "M", color: "red" }, { size: "M", color: "blue" }, | |
| * // { size: "L", color: "red" }, { size: "L", color: "blue" } | |
| * // ] | |
| * | |
| * // Mathematical operations on all pairs | |
| * const a = [1, 2, 3] | |
| * const b = [10, 20] | |
| * const mathProducts = Iterable.cartesianWith(a, b, (x, y) => x * y) | |
| * console.log(Array.from(mathProducts)) // [10, 20, 20, 40, 30, 60] | |
| * | |
| * // Create test data combinations | |
| * const userTypes = ["admin", "user"] | |
| * const features = ["read", "write", "delete"] | |
| * const testCases = Iterable.cartesianWith( | |
| * userTypes, | |
| * features, | |
| * (user, feature) => `${user}_can_${feature}` | |
| * ) | |
| * console.log(Array.from(testCases)) | |
| * // ["admin_can_read", "admin_can_write", "admin_can_delete", "user_can_read", "user_can_write", "user_can_delete"] | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B, C>(self: Iterable<A>, that: Iterable<B>, f: (a: A, b: B) => C): Iterable<C> | |
| } = dual( | |
| 3, | |
| <A, B, C>(self: Iterable<A>, that: Iterable<B>, f: (a: A, b: B) => C): Iterable<C> => | |
| flatMap(self, (a) => map(that, (b) => f(a, b))) | |
| ) | |
| /** | |
| * Zips this Iterable crosswise with the specified Iterable. | |
| * | |
| * **Example** (Generating cartesian pairs) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // All pairs of numbers and letters | |
| * const numbers = [1, 2, 3] | |
| * const letters = ["a", "b"] | |
| * const pairs = Iterable.cartesian(numbers, letters) | |
| * console.log(Array.from(pairs)) | |
| * // [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]] | |
| * | |
| * // Generate coordinate grid | |
| * const x = [0, 1, 2] | |
| * const y = [0, 1] | |
| * const grid = Iterable.cartesian(x, y) | |
| * console.log(Array.from(grid)) | |
| * // [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]] | |
| * | |
| * // All combinations for testing | |
| * const browsers = ["chrome", "firefox"] | |
| * const devices = ["desktop", "mobile", "tablet"] | |
| * const testMatrix = Iterable.cartesian(browsers, devices) | |
| * console.log(Array.from(testMatrix)) | |
| * // [ | |
| * // ["chrome", "desktop"], ["chrome", "mobile"], ["chrome", "tablet"], | |
| * // ["firefox", "desktop"], ["firefox", "mobile"], ["firefox", "tablet"] | |
| * // ] | |
| * | |
| * // Empty iterable results in empty cartesian product | |
| * const empty = Iterable.empty<number>() | |
| * const withEmpty = Iterable.cartesian([1, 2], empty) | |
| * console.log(Array.from(withEmpty)) // [] | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| export const cartesian: { | |
| /** | |
| * Zips this Iterable crosswise with the specified Iterable. | |
| * | |
| * **Example** (Generating cartesian pairs) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // All pairs of numbers and letters | |
| * const numbers = [1, 2, 3] | |
| * const letters = ["a", "b"] | |
| * const pairs = Iterable.cartesian(numbers, letters) | |
| * console.log(Array.from(pairs)) | |
| * // [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]] | |
| * | |
| * // Generate coordinate grid | |
| * const x = [0, 1, 2] | |
| * const y = [0, 1] | |
| * const grid = Iterable.cartesian(x, y) | |
| * console.log(Array.from(grid)) | |
| * // [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]] | |
| * | |
| * // All combinations for testing | |
| * const browsers = ["chrome", "firefox"] | |
| * const devices = ["desktop", "mobile", "tablet"] | |
| * const testMatrix = Iterable.cartesian(browsers, devices) | |
| * console.log(Array.from(testMatrix)) | |
| * // [ | |
| * // ["chrome", "desktop"], ["chrome", "mobile"], ["chrome", "tablet"], | |
| * // ["firefox", "desktop"], ["firefox", "mobile"], ["firefox", "tablet"] | |
| * // ] | |
| * | |
| * // Empty iterable results in empty cartesian product | |
| * const empty = Iterable.empty<number>() | |
| * const withEmpty = Iterable.cartesian([1, 2], empty) | |
| * console.log(Array.from(withEmpty)) // [] | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <B>(that: Iterable<B>): <A>(self: Iterable<A>) => Iterable<[A, B]> | |
| /** | |
| * Zips this Iterable crosswise with the specified Iterable. | |
| * | |
| * **Example** (Generating cartesian pairs) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * // All pairs of numbers and letters | |
| * const numbers = [1, 2, 3] | |
| * const letters = ["a", "b"] | |
| * const pairs = Iterable.cartesian(numbers, letters) | |
| * console.log(Array.from(pairs)) | |
| * // [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]] | |
| * | |
| * // Generate coordinate grid | |
| * const x = [0, 1, 2] | |
| * const y = [0, 1] | |
| * const grid = Iterable.cartesian(x, y) | |
| * console.log(Array.from(grid)) | |
| * // [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]] | |
| * | |
| * // All combinations for testing | |
| * const browsers = ["chrome", "firefox"] | |
| * const devices = ["desktop", "mobile", "tablet"] | |
| * const testMatrix = Iterable.cartesian(browsers, devices) | |
| * console.log(Array.from(testMatrix)) | |
| * // [ | |
| * // ["chrome", "desktop"], ["chrome", "mobile"], ["chrome", "tablet"], | |
| * // ["firefox", "desktop"], ["firefox", "mobile"], ["firefox", "tablet"] | |
| * // ] | |
| * | |
| * // Empty iterable results in empty cartesian product | |
| * const empty = Iterable.empty<number>() | |
| * const withEmpty = Iterable.cartesian([1, 2], empty) | |
| * console.log(Array.from(withEmpty)) // [] | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<[A, B]> | |
| } = dual( | |
| 2, | |
| <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<[A, B]> => cartesianWith(self, that, (a, b) => [a, b]) | |
| ) | |
| /** | |
| * Computes how many elements of the iterable pass the given predicate. | |
| * | |
| * **Example** (Counting matching elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const result = Iterable.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0) | |
| * console.log(result) // 2 | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 3.16.0 | |
| */ | |
| export const countBy: { | |
| /** | |
| * Computes how many elements of the iterable pass the given predicate. | |
| * | |
| * **Example** (Counting matching elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const result = Iterable.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0) | |
| * console.log(result) // 2 | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 3.16.0 | |
| */ | |
| <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => number | |
| /** | |
| * Computes how many elements of the iterable pass the given predicate. | |
| * | |
| * **Example** (Counting matching elements) | |
| * | |
| * ```ts | |
| * import { Iterable } from "effect" | |
| * | |
| * const result = Iterable.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0) | |
| * console.log(result) // 2 | |
| * ``` | |
| * | |
| * @category folding | |
| * @since 3.16.0 | |
| */ | |
| <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): number | |
| } = dual( | |
| 2, | |
| <A>( | |
| self: Iterable<A>, | |
| f: (a: A, i: number) => boolean | |
| ): number => { | |
| let count = 0 | |
| let i = 0 | |
| for (const a of self) { | |
| if (f(a, i)) { | |
| count++ | |
| } | |
| i++ | |
| } | |
| return count | |
| } | |
| ) | |
Xet Storage Details
- Size:
- 164 kB
- Xet hash:
- f77fac3ec904014e8becc6a27108a27d4beb0843f9bafbe78ad6afa84a11466e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.