UNPKG

effect

Version:

The missing standard library for TypeScript, for writing production-grade software.

1,868 lines (1,815 loc) 195 kB
/** * This module provides utility functions for working with arrays in TypeScript. * * @since 2.0.0 */ import * as Either from "./Either.js" import * as Equal from "./Equal.js" import * as Equivalence from "./Equivalence.js" import type { LazyArg } from "./Function.js" import { dual, identity } from "./Function.js" import type { TypeLambda } from "./HKT.js" import * as internalArray from "./internal/array.js" import * as internalDoNotation from "./internal/doNotation.js" import * as moduleIterable from "./Iterable.js" import * as Option from "./Option.js" import * as Order from "./Order.js" import * as Predicate from "./Predicate.js" import * as Record from "./Record.js" import * as Tuple from "./Tuple.js" import type { NoInfer, TupleOf } from "./Types.js" /** * @category type lambdas * @since 2.0.0 */ export interface ReadonlyArrayTypeLambda extends TypeLambda { readonly type: ReadonlyArray<this["Target"]> } /** * @category models * @since 2.0.0 */ export type NonEmptyReadonlyArray<A> = readonly [A, ...Array<A>] /** * @category models * @since 2.0.0 */ export type NonEmptyArray<A> = [A, ...Array<A>] /** * Builds a `NonEmptyArray` from an non-empty collection of elements. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.make(1, 2, 3) * console.log(result) // [1, 2, 3] * ``` * * @category constructors * @since 2.0.0 */ export const make = <Elements extends NonEmptyArray<any>>( ...elements: Elements ): NonEmptyArray<Elements[number]> => elements /** * Creates a new `Array` of the specified length. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.allocate<number>(3) * console.log(result) // [ <3 empty items> ] * ``` * * @category constructors * @since 2.0.0 */ export const allocate = <A = never>(n: number): Array<A | undefined> => new Array(n) /** * Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. * * **Note**. `n` is normalized to an integer >= 1. * * **Example** * * ```ts * import { makeBy } from "effect/Array" * * const result = makeBy(5, n => n * 2) * console.log(result) // [0, 2, 4, 6, 8] * ``` * * @category constructors * @since 2.0.0 */ export const makeBy: { /** * Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. * * **Note**. `n` is normalized to an integer >= 1. * * **Example** * * ```ts * import { makeBy } from "effect/Array" * * const result = makeBy(5, n => n * 2) * console.log(result) // [0, 2, 4, 6, 8] * ``` * * @category constructors * @since 2.0.0 */ <A>(f: (i: number) => A): (n: number) => NonEmptyArray<A> /** * Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. * * **Note**. `n` is normalized to an integer >= 1. * * **Example** * * ```ts * import { makeBy } from "effect/Array" * * const result = makeBy(5, n => n * 2) * console.log(result) // [0, 2, 4, 6, 8] * ``` * * @category constructors * @since 2.0.0 */ <A>(n: number, f: (i: number) => A): NonEmptyArray<A> } = dual(2, <A>(n: number, f: (i: number) => A) => { const max = Math.max(1, Math.floor(n)) const out = new Array(max) for (let i = 0; i < max; i++) { out[i] = f(i) } return out as NonEmptyArray<A> }) /** * Return a `NonEmptyArray` containing a range of integers, including both endpoints. * * **Example** * * ```ts * import { range } from "effect/Array" * * const result = range(1, 3) * console.log(result) // [1, 2, 3] * ``` * * @category constructors * @since 2.0.0 */ export const range = (start: number, end: number): NonEmptyArray<number> => start <= end ? makeBy(end - start + 1, (i) => start + i) : [start] /** * Return a `NonEmptyArray` containing a value repeated the specified number of times. * * **Note**. `n` is normalized to an integer >= 1. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.replicate("a", 3) * console.log(result) // ["a", "a", "a"] * ``` * * @category constructors * @since 2.0.0 */ export const replicate: { /** * Return a `NonEmptyArray` containing a value repeated the specified number of times. * * **Note**. `n` is normalized to an integer >= 1. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.replicate("a", 3) * console.log(result) // ["a", "a", "a"] * ``` * * @category constructors * @since 2.0.0 */ (n: number): <A>(a: A) => NonEmptyArray<A> /** * Return a `NonEmptyArray` containing a value repeated the specified number of times. * * **Note**. `n` is normalized to an integer >= 1. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.replicate("a", 3) * console.log(result) // ["a", "a", "a"] * ``` * * @category constructors * @since 2.0.0 */ <A>(a: A, n: number): NonEmptyArray<A> } = dual(2, <A>(a: A, n: number): NonEmptyArray<A> => makeBy(n, () => a)) /** * Creates a new `Array` from an iterable collection of values. * If the input is already an array, it returns the input as-is. * Otherwise, it converts the iterable collection to an array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.fromIterable(new Set([1, 2, 3])) * console.log(result) // [1, 2, 3] * ``` * * @category constructors * @since 2.0.0 */ export const fromIterable = <A>(collection: Iterable<A>): Array<A> => Array.isArray(collection) ? collection : Array.from(collection) /** * Creates a new `Array` from a value that might not be an iterable. * * **Example** * * ```ts * import { Array } from "effect" * * console.log(Array.ensure("a")) // ["a"] * console.log(Array.ensure(["a"])) // ["a"] * console.log(Array.ensure(["a", "b", "c"])) // ["a", "b", "c"] * ``` * * @category constructors * @since 3.3.0 */ export const ensure = <A>(self: ReadonlyArray<A> | A): Array<A> => Array.isArray(self) ? self : [self as A] /** * Takes a record and returns an array of tuples containing its keys and values. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.fromRecord({ a: 1, b: 2, c: 3 }) * console.log(result) // [["a", 1], ["b", 2], ["c", 3]] * ``` * * @category conversions * @since 2.0.0 */ export const fromRecord: <K extends string, A>(self: Readonly<Record<K, A>>) => Array<[K, A]> = Record.toEntries /** * Converts an `Option` to an array. * * **Example** * * ```ts * import { Array, Option } from "effect" * * console.log(Array.fromOption(Option.some(1))) // [1] * console.log(Array.fromOption(Option.none())) // [] * ``` * * @category conversions * @since 2.0.0 */ export const fromOption: <A>(self: Option.Option<A>) => Array<A> = Option.toArray /** * Matches the elements of an array, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const match = Array.match({ * onEmpty: () => "empty", * onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}` * }) * console.log(match([])) // "empty" * console.log(match([1, 2, 3])) // "head: 1, tail: 2" * ``` * * @category pattern matching * @since 2.0.0 */ export const match: { /** * Matches the elements of an array, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const match = Array.match({ * onEmpty: () => "empty", * onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}` * }) * console.log(match([])) // "empty" * console.log(match([1, 2, 3])) // "head: 1, tail: 2" * ``` * * @category pattern matching * @since 2.0.0 */ <B, A, C = B>( options: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (self: NonEmptyReadonlyArray<A>) => C } ): (self: ReadonlyArray<A>) => B | C /** * Matches the elements of an array, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const match = Array.match({ * onEmpty: () => "empty", * onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}` * }) * console.log(match([])) // "empty" * console.log(match([1, 2, 3])) // "head: 1, tail: 2" * ``` * * @category pattern matching * @since 2.0.0 */ <A, B, C = B>( self: ReadonlyArray<A>, options: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (self: NonEmptyReadonlyArray<A>) => C } ): B | C } = dual(2, <A, B, C = B>( self: ReadonlyArray<A>, { onEmpty, onNonEmpty }: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (self: NonEmptyReadonlyArray<A>) => C } ): B | C => isNonEmptyReadonlyArray(self) ? onNonEmpty(self) : onEmpty()) /** * Matches the elements of an array from the left, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const matchLeft = Array.matchLeft({ * onEmpty: () => "empty", * onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}` * }) * console.log(matchLeft([])) // "empty" * console.log(matchLeft([1, 2, 3])) // "head: 1, tail: 2" * ``` * * @category pattern matching * @since 2.0.0 */ export const matchLeft: { /** * Matches the elements of an array from the left, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const matchLeft = Array.matchLeft({ * onEmpty: () => "empty", * onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}` * }) * console.log(matchLeft([])) // "empty" * console.log(matchLeft([1, 2, 3])) // "head: 1, tail: 2" * ``` * * @category pattern matching * @since 2.0.0 */ <B, A, C = B>( options: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (head: A, tail: Array<A>) => C } ): (self: ReadonlyArray<A>) => B | C /** * Matches the elements of an array from the left, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const matchLeft = Array.matchLeft({ * onEmpty: () => "empty", * onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}` * }) * console.log(matchLeft([])) // "empty" * console.log(matchLeft([1, 2, 3])) // "head: 1, tail: 2" * ``` * * @category pattern matching * @since 2.0.0 */ <A, B, C = B>( self: ReadonlyArray<A>, options: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (head: A, tail: Array<A>) => C } ): B | C } = dual(2, <A, B, C = B>( self: ReadonlyArray<A>, { onEmpty, onNonEmpty }: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (head: A, tail: Array<A>) => C } ): B | C => isNonEmptyReadonlyArray(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty()) /** * Matches the elements of an array from the right, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const matchRight = Array.matchRight({ * onEmpty: () => "empty", * onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}` * }) * console.log(matchRight([])) // "empty" * console.log(matchRight([1, 2, 3])) // "init: 2, last: 3" * ``` * * @category pattern matching * @since 2.0.0 */ export const matchRight: { /** * Matches the elements of an array from the right, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const matchRight = Array.matchRight({ * onEmpty: () => "empty", * onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}` * }) * console.log(matchRight([])) // "empty" * console.log(matchRight([1, 2, 3])) // "init: 2, last: 3" * ``` * * @category pattern matching * @since 2.0.0 */ <B, A, C = B>( options: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (init: Array<A>, last: A) => C } ): (self: ReadonlyArray<A>) => B | C /** * Matches the elements of an array from the right, applying functions to cases of empty and non-empty arrays. * * **Example** * * ```ts * import { Array } from "effect" * * const matchRight = Array.matchRight({ * onEmpty: () => "empty", * onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}` * }) * console.log(matchRight([])) // "empty" * console.log(matchRight([1, 2, 3])) // "init: 2, last: 3" * ``` * * @category pattern matching * @since 2.0.0 */ <A, B, C = B>( self: ReadonlyArray<A>, options: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (init: Array<A>, last: A) => C } ): B | C } = dual(2, <A, B, C = B>( self: ReadonlyArray<A>, { onEmpty, onNonEmpty }: { readonly onEmpty: LazyArg<B> readonly onNonEmpty: (init: Array<A>, last: A) => C } ): B | C => isNonEmptyReadonlyArray(self) ? onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) : onEmpty()) /** * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.prepend([2, 3, 4], 1) * console.log(result) // [1, 2, 3, 4] * ``` * * @category concatenating * @since 2.0.0 */ export const prepend: { /** * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.prepend([2, 3, 4], 1) * console.log(result) // [1, 2, 3, 4] * ``` * * @category concatenating * @since 2.0.0 */ <B>(head: B): <A>(self: Iterable<A>) => NonEmptyArray<A | B> /** * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.prepend([2, 3, 4], 1) * console.log(result) // [1, 2, 3, 4] * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: Iterable<A>, head: B): NonEmptyArray<A | B> } = dual(2, <A, B>(self: Iterable<A>, head: B): NonEmptyArray<A | B> => [head, ...self]) /** * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). * If either array is non-empty, the result is also a non-empty array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.prependAll([2, 3], [0, 1]) * console.log(result) // [0, 1, 2, 3] * ``` * * @category concatenating * @since 2.0.0 */ export const prependAll: { /** * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). * If either array is non-empty, the result is also a non-empty array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.prependAll([2, 3], [0, 1]) * console.log(result) // [0, 1, 2, 3] * ``` * * @category concatenating * @since 2.0.0 */ <S extends Iterable<any>, T extends Iterable<any>>(that: T): (self: S) => ReadonlyArray.OrNonEmpty<S, T, ReadonlyArray.Infer<S> | ReadonlyArray.Infer<T>> /** * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). * If either array is non-empty, the result is also a non-empty array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.prependAll([2, 3], [0, 1]) * console.log(result) // [0, 1, 2, 3] * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: Iterable<A>, that: NonEmptyReadonlyArray<B>): NonEmptyArray<A | B> /** * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). * If either array is non-empty, the result is also a non-empty array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.prependAll([2, 3], [0, 1]) * console.log(result) // [0, 1, 2, 3] * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: NonEmptyReadonlyArray<A>, that: Iterable<B>): NonEmptyArray<A | B> /** * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). * If either array is non-empty, the result is also a non-empty array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.prependAll([2, 3], [0, 1]) * console.log(result) // [0, 1, 2, 3] * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: Iterable<A>, that: Iterable<B>): Array<A | B> } = dual( 2, <A>(self: Iterable<A>, that: Iterable<A>): Array<A> => fromIterable(that).concat(fromIterable(self)) ) /** * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.append([1, 2, 3], 4); * console.log(result) // [1, 2, 3, 4] * ``` * * @category concatenating * @since 2.0.0 */ export const append: { /** * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.append([1, 2, 3], 4); * console.log(result) // [1, 2, 3, 4] * ``` * * @category concatenating * @since 2.0.0 */ <B>(last: B): <A>(self: Iterable<A>) => NonEmptyArray<A | B> /** * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.append([1, 2, 3], 4); * console.log(result) // [1, 2, 3, 4] * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: Iterable<A>, last: B): NonEmptyArray<A | B> } = dual(2, <A, B>(self: Iterable<A>, last: B): Array<A | B> => [...self, last]) /** * Concatenates two arrays (or iterables), combining their elements. * If either array is non-empty, the result is also a non-empty array. * * @category concatenating * @since 2.0.0 */ export const appendAll: { /** * Concatenates two arrays (or iterables), combining their elements. * If either array is non-empty, the result is also a non-empty array. * * @category concatenating * @since 2.0.0 */ <S extends Iterable<any>, T extends Iterable<any>>(that: T): (self: S) => ReadonlyArray.OrNonEmpty<S, T, ReadonlyArray.Infer<S> | ReadonlyArray.Infer<T>> /** * Concatenates two arrays (or iterables), combining their elements. * If either array is non-empty, the result is also a non-empty array. * * @category concatenating * @since 2.0.0 */ <A, B>(self: Iterable<A>, that: NonEmptyReadonlyArray<B>): NonEmptyArray<A | B> /** * Concatenates two arrays (or iterables), combining their elements. * If either array is non-empty, the result is also a non-empty array. * * @category concatenating * @since 2.0.0 */ <A, B>(self: NonEmptyReadonlyArray<A>, that: Iterable<B>): NonEmptyArray<A | B> /** * Concatenates two arrays (or iterables), combining their elements. * If either array is non-empty, the result is also a non-empty array. * * @category concatenating * @since 2.0.0 */ <A, B>(self: Iterable<A>, that: Iterable<B>): Array<A | B> } = dual( 2, <A>(self: Iterable<A>, that: Iterable<A>): Array<A> => fromIterable(self).concat(fromIterable(that)) ) /** * Accumulates values from an `Iterable` starting from the left, storing * each intermediate result in an array. Useful for tracking the progression of * a value through a series of transformations. * * **Example** * * ```ts * import { Array } from "effect"; * * const result = Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value) * console.log(result) // [0, 1, 3, 6, 10] * * // Explanation: * // This function starts with the initial value (0 in this case) * // and adds each element of the array to this accumulator one by one, * // keeping track of the cumulative sum after each addition. * // Each of these sums is captured in the resulting array. * ``` * * @category folding * @since 2.0.0 */ export const scan: { /** * Accumulates values from an `Iterable` starting from the left, storing * each intermediate result in an array. Useful for tracking the progression of * a value through a series of transformations. * * **Example** * * ```ts * import { Array } from "effect"; * * const result = Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value) * console.log(result) // [0, 1, 3, 6, 10] * * // Explanation: * // This function starts with the initial value (0 in this case) * // and adds each element of the array to this accumulator one by one, * // keeping track of the cumulative sum after each addition. * // Each of these sums is captured in the resulting array. * ``` * * @category folding * @since 2.0.0 */ <B, A>(b: B, f: (b: B, a: A) => B): (self: Iterable<A>) => NonEmptyArray<B> /** * Accumulates values from an `Iterable` starting from the left, storing * each intermediate result in an array. Useful for tracking the progression of * a value through a series of transformations. * * **Example** * * ```ts * import { Array } from "effect"; * * const result = Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value) * console.log(result) // [0, 1, 3, 6, 10] * * // Explanation: * // This function starts with the initial value (0 in this case) * // and adds each element of the array to this accumulator one by one, * // keeping track of the cumulative sum after each addition. * // Each of these sums is captured in the resulting array. * ``` * * @category folding * @since 2.0.0 */ <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): NonEmptyArray<B> } = dual(3, <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): NonEmptyArray<B> => { const out: NonEmptyArray<B> = [b] let i = 0 for (const a of self) { out[i + 1] = f(out[i], a) i++ } return out }) /** * Accumulates values from an `Iterable` starting from the right, storing * each intermediate result in an array. Useful for tracking the progression of * a value through a series of transformations. * * **Example** * * ```ts * import { Array } from "effect"; * * const result = Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value) * console.log(result) // [10, 9, 7, 4, 0] * ``` * * @category folding * @since 2.0.0 */ export const scanRight: { /** * Accumulates values from an `Iterable` starting from the right, storing * each intermediate result in an array. Useful for tracking the progression of * a value through a series of transformations. * * **Example** * * ```ts * import { Array } from "effect"; * * const result = Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value) * console.log(result) // [10, 9, 7, 4, 0] * ``` * * @category folding * @since 2.0.0 */ <B, A>(b: B, f: (b: B, a: A) => B): (self: Iterable<A>) => NonEmptyArray<B> /** * Accumulates values from an `Iterable` starting from the right, storing * each intermediate result in an array. Useful for tracking the progression of * a value through a series of transformations. * * **Example** * * ```ts * import { Array } from "effect"; * * const result = Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value) * console.log(result) // [10, 9, 7, 4, 0] * ``` * * @category folding * @since 2.0.0 */ <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): NonEmptyArray<B> } = dual(3, <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): NonEmptyArray<B> => { const input = fromIterable(self) const out: NonEmptyArray<B> = new Array(input.length + 1) as any out[input.length] = b for (let i = input.length - 1; i >= 0; i--) { out[i] = f(out[i + 1], input[i]) } return out }) /** * Determine if `unknown` is an Array. * * **Example** * * ```ts * import { Array } from "effect" * * console.log(Array.isArray(null)) // false * console.log(Array.isArray([1, 2, 3])) // true * ``` * * @category guards * @since 2.0.0 */ export const isArray: { /** * Determine if `unknown` is an Array. * * **Example** * * ```ts * import { Array } from "effect" * * console.log(Array.isArray(null)) // false * console.log(Array.isArray([1, 2, 3])) // true * ``` * * @category guards * @since 2.0.0 */ (self: unknown): self is Array<unknown> /** * Determine if `unknown` is an Array. * * **Example** * * ```ts * import { Array } from "effect" * * console.log(Array.isArray(null)) // false * console.log(Array.isArray([1, 2, 3])) // true * ``` * * @category guards * @since 2.0.0 */ <T>(self: T): self is Extract<T, ReadonlyArray<any>> } = Array.isArray /** * Determine if an `Array` is empty narrowing down the type to `[]`. * * **Example** * * ```ts * import { Array } from "effect" * * console.log(Array.isEmptyArray([])) // true * console.log(Array.isEmptyArray([1, 2, 3])) // false * ``` * * @category guards * @since 2.0.0 */ export const isEmptyArray = <A>(self: Array<A>): self is [] => self.length === 0 /** * Determine if a `ReadonlyArray` is empty narrowing down the type to `readonly []`. * * **Example** * * ```ts * import { Array } from "effect" * * console.log(Array.isEmptyReadonlyArray([])) // true * console.log(Array.isEmptyReadonlyArray([1, 2, 3])) // false * ``` * * @category guards * @since 2.0.0 */ export const isEmptyReadonlyArray: <A>(self: ReadonlyArray<A>) => self is readonly [] = isEmptyArray as any /** * Determine if an `Array` is non empty narrowing down the type to `NonEmptyArray`. * * An `Array` is considered to be a `NonEmptyArray` if it contains at least one element. * * **Example** * * ```ts * import { Array } from "effect" * * console.log(Array.isNonEmptyArray([])) // false * console.log(Array.isNonEmptyArray([1, 2, 3])) // true * ``` * * @category guards * @since 2.0.0 */ export const isNonEmptyArray: <A>(self: Array<A>) => self is NonEmptyArray<A> = internalArray.isNonEmptyArray /** * Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. * * A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. * * **Example** * * ```ts * import { Array } from "effect" * * console.log(Array.isNonEmptyReadonlyArray([])) // false * console.log(Array.isNonEmptyReadonlyArray([1, 2, 3])) // true * ``` * * @category guards * @since 2.0.0 */ export const isNonEmptyReadonlyArray: <A>(self: ReadonlyArray<A>) => self is NonEmptyReadonlyArray<A> = internalArray.isNonEmptyArray /** * Return the number of elements in a `ReadonlyArray`. * * @category getters * @since 2.0.0 */ export const length = <A>(self: ReadonlyArray<A>): number => self.length const isOutOfBounds = <A>(i: number, as: ReadonlyArray<A>): boolean => i < 0 || i >= as.length const clamp = <A>(i: number, as: ReadonlyArray<A>): number => Math.floor(Math.min(Math.max(0, i), as.length)) /** * This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. * * @category getters * @since 2.0.0 */ export const get: { /** * This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. * * @category getters * @since 2.0.0 */ (index: number): <A>(self: ReadonlyArray<A>) => Option.Option<A> /** * This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. * * @category getters * @since 2.0.0 */ <A>(self: ReadonlyArray<A>, index: number): Option.Option<A> } = dual(2, <A>(self: ReadonlyArray<A>, index: number): Option.Option<A> => { const i = Math.floor(index) return isOutOfBounds(i, self) ? Option.none() : Option.some(self[i]) }) /** * Gets an element unsafely, will throw on out of bounds. * * @since 2.0.0 * @category unsafe */ export const unsafeGet: { /** * Gets an element unsafely, will throw on out of bounds. * * @since 2.0.0 * @category unsafe */ (index: number): <A>(self: ReadonlyArray<A>) => A /** * Gets an element unsafely, will throw on out of bounds. * * @since 2.0.0 * @category unsafe */ <A>(self: ReadonlyArray<A>, index: number): A } = dual(2, <A>(self: ReadonlyArray<A>, index: number): A => { const i = Math.floor(index) if (isOutOfBounds(i, self)) { throw new Error(`Index ${i} out of bounds`) } return self[i] }) /** * Return a tuple containing the first element, and a new `Array` of the remaining elements, if any. * * **Example** * * ```ts * import { Array } from "effect"; * * const result = Array.unprepend([1, 2, 3, 4]) * console.log(result) // [1, [2, 3, 4]] * ``` * * @category splitting * @since 2.0.0 */ export const unprepend = <A>( self: NonEmptyReadonlyArray<A> ): [firstElement: A, remainingElements: Array<A>] => [headNonEmpty(self), tailNonEmpty(self)] /** * Return a tuple containing a copy of the `NonEmptyReadonlyArray` without its last element, and that last element. * * **Example** * * ```ts * import { Array } from "effect"; * * const result = Array.unappend([1, 2, 3, 4]) * console.log(result) // [[1, 2, 3], 4] * ``` * * @category splitting * @since 2.0.0 */ export const unappend = <A>( self: NonEmptyReadonlyArray<A> ): [arrayWithoutLastElement: Array<A>, lastElement: A] => [initNonEmpty(self), lastNonEmpty(self)] /** * Get the first element of a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. * * @category getters * @since 2.0.0 */ export const head: <A>(self: ReadonlyArray<A>) => Option.Option<A> = get(0) /** * Get the first element of a non empty array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.headNonEmpty([1, 2, 3, 4]) * console.log(result) // 1 * ``` * * @category getters * @since 2.0.0 */ export const headNonEmpty: <A>(self: NonEmptyReadonlyArray<A>) => A = unsafeGet(0) /** * Get the last element in a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. * * @category getters * @since 2.0.0 */ export const last = <A>(self: ReadonlyArray<A>): Option.Option<A> => isNonEmptyReadonlyArray(self) ? Option.some(lastNonEmpty(self)) : Option.none() /** * Get the last element of a non empty array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.lastNonEmpty([1, 2, 3, 4]) * console.log(result) // 4 * ``` * * @category getters * @since 2.0.0 */ export const lastNonEmpty = <A>(self: NonEmptyReadonlyArray<A>): A => self[self.length - 1] /** * Get all but the first element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. * * @category getters * @since 2.0.0 */ export const tail = <A>(self: Iterable<A>): Option.Option<Array<A>> => { const input = fromIterable(self) return isNonEmptyReadonlyArray(input) ? Option.some(tailNonEmpty(input)) : Option.none() } /** * Get all but the first element of a `NonEmptyReadonlyArray`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.tailNonEmpty([1, 2, 3, 4]) * console.log(result) // [2, 3, 4] * ``` * * @category getters * @since 2.0.0 */ export const tailNonEmpty = <A>(self: NonEmptyReadonlyArray<A>): Array<A> => self.slice(1) /** * Get all but the last element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. * * @category getters * @since 2.0.0 */ export const init = <A>(self: Iterable<A>): Option.Option<Array<A>> => { const input = fromIterable(self) return isNonEmptyReadonlyArray(input) ? Option.some(initNonEmpty(input)) : Option.none() } /** * Get all but the last element of a non empty array, creating a new array. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.initNonEmpty([1, 2, 3, 4]) * console.log(result) // [1, 2, 3] * ``` * * @category getters * @since 2.0.0 */ export const initNonEmpty = <A>(self: NonEmptyReadonlyArray<A>): Array<A> => self.slice(0, -1) /** * Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.take([1, 2, 3, 4, 5], 3) * console.log(result) // [1, 2, 3] * ``` * * @category getters * @since 2.0.0 */ export const take: { /** * Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.take([1, 2, 3, 4, 5], 3) * console.log(result) // [1, 2, 3] * ``` * * @category getters * @since 2.0.0 */ (n: number): <A>(self: Iterable<A>) => Array<A> /** * Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.take([1, 2, 3, 4, 5], 3) * console.log(result) // [1, 2, 3] * ``` * * @category getters * @since 2.0.0 */ <A>(self: Iterable<A>, n: number): Array<A> } = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => { const input = fromIterable(self) return input.slice(0, clamp(n, input)) }) /** * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.takeRight([1, 2, 3, 4, 5], 3) * console.log(result) // [3, 4, 5] * ``` * * @category getters * @since 2.0.0 */ export const takeRight: { /** * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.takeRight([1, 2, 3, 4, 5], 3) * console.log(result) // [3, 4, 5] * ``` * * @category getters * @since 2.0.0 */ (n: number): <A>(self: Iterable<A>) => Array<A> /** * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.takeRight([1, 2, 3, 4, 5], 3) * console.log(result) // [3, 4, 5] * ``` * * @category getters * @since 2.0.0 */ <A>(self: Iterable<A>, n: number): Array<A> } = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => { const input = fromIterable(self) const i = clamp(n, input) return i === 0 ? [] : input.slice(-i) }) /** * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) * console.log(result) // [1, 3, 2] * * // Explanation: * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. * // - The next element (`3`) is also less than `4`, so it adds `3`. * // - The next element (`2`) is again less than `4`, so it adds `2`. * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. * ``` * * @category getters * @since 2.0.0 */ export const takeWhile: { /** * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) * console.log(result) // [1, 3, 2] * * // Explanation: * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. * // - The next element (`3`) is also less than `4`, so it adds `3`. * // - The next element (`2`) is again less than `4`, so it adds `2`. * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. * ``` * * @category getters * @since 2.0.0 */ <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Array<B> /** * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) * console.log(result) // [1, 3, 2] * * // Explanation: * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. * // - The next element (`3`) is also less than `4`, so it adds `3`. * // - The next element (`2`) is again less than `4`, so it adds `2`. * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. * ``` * * @category getters * @since 2.0.0 */ <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Array<A> /** * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) * console.log(result) // [1, 3, 2] * * // Explanation: * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. * // - The next element (`3`) is also less than `4`, so it adds `3`. * // - The next element (`2`) is again less than `4`, so it adds `2`. * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. * ``` * * @category getters * @since 2.0.0 */ <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Array<B> /** * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) * console.log(result) // [1, 3, 2] * * // Explanation: * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. * // - The next element (`3`) is also less than `4`, so it adds `3`. * // - The next element (`2`) is again less than `4`, so it adds `2`. * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. * ``` * * @category getters * @since 2.0.0 */ <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A> } = dual(2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A> => { let i = 0 const out: Array<A> = [] for (const a of self) { if (!predicate(a, i)) { break } out.push(a) i++ } return out }) const spanIndex = <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): number => { let i = 0 for (const a of self) { if (!predicate(a, i)) { break } i++ } return i } /** * Split an `Iterable` into two parts: * * 1. the longest initial subarray for which all elements satisfy the specified predicate * 2. the remaining elements * * @category splitting * @since 2.0.0 */ export const span: { /** * Split an `Iterable` into two parts: * * 1. the longest initial subarray for which all elements satisfy the specified predicate * 2. the remaining elements * * @category splitting * @since 2.0.0 */ <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => [init: Array<B>, rest: Array<Exclude<A, B>>] /** * Split an `Iterable` into two parts: * * 1. the longest initial subarray for which all elements satisfy the specified predicate * 2. the remaining elements * * @category splitting * @since 2.0.0 */ <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => [init: Array<A>, rest: Array<A>] /** * Split an `Iterable` into two parts: * * 1. the longest initial subarray for which all elements satisfy the specified predicate * 2. the remaining elements * * @category splitting * @since 2.0.0 */ <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): [init: Array<B>, rest: Array<Exclude<A, B>>] /** * Split an `Iterable` into two parts: * * 1. the longest initial subarray for which all elements satisfy the specified predicate * 2. the remaining elements * * @category splitting * @since 2.0.0 */ <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): [init: Array<A>, rest: Array<A>] } = dual( 2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): [init: Array<A>, rest: Array<A>] => splitAt(self, spanIndex(self, predicate)) ) /** * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.drop([1, 2, 3, 4, 5], 2) * console.log(result) // [3, 4, 5] * ``` * * @category getters * @since 2.0.0 */ export const drop: { /** * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.drop([1, 2, 3, 4, 5], 2) * console.log(result) // [3, 4, 5] * ``` * * @category getters * @since 2.0.0 */ (n: number): <A>(self: Iterable<A>) => Array<A> /** * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.drop([1, 2, 3, 4, 5], 2) * console.log(result) // [3, 4, 5] * ``` * * @category getters * @since 2.0.0 */ <A>(self: Iterable<A>, n: number): Array<A> } = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => { const input = fromIterable(self) return input.slice(clamp(n, input), input.length) }) /** * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.dropRight([1, 2, 3, 4, 5], 2) * console.log(result) // [1, 2, 3] * ``` * * @category getters * @since 2.0.0 */ export const dropRight: { /** * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.dropRight([1, 2, 3, 4, 5], 2) * console.log(result) // [1, 2, 3] * ``` * * @category getters * @since 2.0.0 */ (n: number): <A>(self: Iterable<A>) => Array<A> /** * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.dropRight([1, 2, 3, 4, 5], 2) * console.log(result) // [1, 2, 3] * ``` * * @category getters * @since 2.0.0 */ <A>(self: Iterable<A>, n: number): Array<A> } = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => { const input = fromIterable(self) return input.slice(0, input.length - clamp(n, input)) }) /** * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.dropWhile([1, 2, 3, 4, 5], x => x < 4) * console.log(result) // [4, 5] * ``` * * @category getters * @since 2.0.0 */ export const dropWhile: { /** * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.dropWhile([1, 2, 3, 4, 5], x => x < 4) * console.log(result) // [4, 5] * ``` * * @category getters * @since 2.0.0 */ <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Array<A> /** * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.dropWhile([1, 2, 3, 4, 5], x => x < 4) * console.log(result) // [4, 5] * ``` * * @category getters * @since 2.0.0 */ <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A> } = dual( 2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A> => fromIterable(self).slice(spanIndex(self, predicate)) ) /** * Return the first index for which a predicate holds. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.findFirstIndex([5, 3, 8, 9], x => x > 5) * console.log(result) // Option.some(2) * ``` * * @category elements * @since 2.0.0 */ export const findFirstIndex: { /** * Return the first index for which a predicate holds. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.findFirstIndex([5, 3, 8, 9], x => x > 5) * console.log(result) // Option.some(2) * ``` * * @category elements * @since 2.0.0 */ <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option.Option<number> /** * Return the first index for which a predicate holds. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.findFirstIndex([5, 3, 8, 9], x => x > 5) * console.log(result) // Option.some(2) * ``` * * @category elements * @since 2.0.0 */ <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<number> } = dual(2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<number> => { let i = 0 for (const a of self) { if (predicate(a, i)) { return Option.some(i) } i++ } return Option.none() }) /** * Return the last index for which a predicate holds. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.findLastIndex([1, 3, 8, 9], x => x < 5) * console.log(result) // Option.some(1) * ``` * * @category elements * @since 2.0.0 */ export const findLastIndex: { /** * Return the last index for which a predicate holds. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.findLastIndex([1, 3, 8, 9], x => x < 5) * console.log(result) // Option.some(1) * ``` * * @category elements * @since 2.0.0 */ <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option.Option<number> /** * Return the last index for which a predicate holds. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.findLastIndex([1, 3, 8, 9], x => x < 5) * console.log(result) // Option.some(1) * ``` * * @category elements * @since 2.0.0 */ <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<number> } = dual(2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<number> => { const input = fromIterable(self) for (let i = input.length - 1; i >= 0; i--) { if (predicate(input[i], i)) { return Option.some(i) } } return Option.none() }) /** * Returns the first element that satisfies the specified * predicate, or `None` if no such element exists. * * **Example** * * ```ts * import { Array } from "effect" * * const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3) * console.log(result) // Option.some(4) * ``` * * @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** * * ```ts * import { Array } from "effect" * * const result = Arr