/**
* Utilities for working with immutable arrays (and non-empty arrays) in a
* functional style. All functions treat arrays as immutable — they return new
* arrays rather than mutating the input.
*
* ## Mental model
*
* - **`Array`** is a standard JS array. All functions in this module return
* new arrays; the input is never mutated.
* - **`NonEmptyReadonlyArray`** (`readonly [A, ...Array]`) is a readonly
* array guaranteed to have at least one element. Many functions preserve or
* require this guarantee at the type level.
* - **`NonEmptyArray`** is the mutable counterpart: `[A, ...Array]`.
* - Most functions are **dual** — they can be called either as
* `Array.fn(array, arg)` (data-first) or piped as
* `pipe(array, Array.fn(arg))` (data-last).
* - Functions that access elements by index return `Option` for safety; use
* the `*NonEmpty` variants (e.g. {@link headNonEmpty}) when you already know
* the array is non-empty.
* - Set-like operations ({@link union}, {@link intersection},
* {@link difference}) use `Equal.equivalence()` by default; use the `*With`
* variants for custom equality.
*
* ## Common tasks
*
* - **Create** an array: {@link make}, {@link of}, {@link empty},
* {@link fromIterable}, {@link range}, {@link makeBy}, {@link replicate},
* {@link unfold}
* - **Access** elements: {@link head}, {@link last}, {@link get}, {@link tail},
* {@link init}
* - **Transform**: {@link map}, {@link flatMap}, {@link flatten}
* - **Filter**: {@link filter}, {@link partition}, {@link dedupe}
* - **Combine**: {@link append}, {@link prepend}, {@link appendAll},
* {@link prependAll}, {@link zip}, {@link cartesian}
* - **Split**: {@link splitAt}, {@link chunksOf}, {@link span}, {@link window}
* - **Search**: {@link findFirst}, {@link findLast}, {@link contains}
* - **Sort**: {@link sort}, {@link sortBy}, {@link sortWith}
* - **Fold**: {@link reduce}, {@link scan}, {@link join}
* - **Group**: {@link groupBy}, {@link group}, {@link groupWith}
* - **Set operations**: {@link union}, {@link intersection},
* {@link difference}
* - **Match** on empty vs non-empty: {@link match}, {@link matchLeft},
* {@link matchRight}
* - **Check** properties: {@link isArray}, {@link isArrayNonEmpty},
* {@link every}, {@link some}
*
* ## Gotchas
*
* - {@link fromIterable} returns the original array reference when given an
* array; if you need a copy, use {@link copy}.
* - `sort`, `reverse`, etc. always allocate a new array — the input is never
* mutated.
* - {@link makeBy} and {@link replicate} normalize `n` to an integer >= 1 —
* they never produce an empty array.
* - {@link range}`(start, end)` is inclusive on both ends. If `start > end` it
* returns `[start]`.
* - Functions returning `Option` (e.g. {@link head}, {@link findFirst}) return
* `Option.none()` for empty inputs — they never throw.
*
* ## Quickstart
*
* **Example** (Basic array operations)
*
* ```ts
* import { Array } from "effect"
*
* const numbers = Array.make(1, 2, 3, 4, 5)
*
* const doubled = Array.map(numbers, (n) => n * 2)
* console.log(doubled) // [2, 4, 6, 8, 10]
*
* const evens = Array.filter(numbers, (n) => n % 2 === 0)
* console.log(evens) // [2, 4]
*
* const sum = Array.reduce(numbers, 0, (acc, n) => acc + n)
* console.log(sum) // 15
* ```
*
* @see {@link make} — create a non-empty array from elements
* @see {@link map} — transform each element
* @see {@link filter} — keep elements matching a predicate
* @see {@link reduce} — fold an array to a single value
*
* @since 2.0.0
*/
import * as Equal from "./Equal.ts"
import * as Equivalence from "./Equivalence.ts"
import type { LazyArg } from "./Function.ts"
import { dual, identity } from "./Function.ts"
import type { TypeLambda } from "./HKT.ts"
import * as internalArray from "./internal/array.ts"
import * as internalDoNotation from "./internal/doNotation.ts"
import * as moduleIterable from "./Iterable.ts"
import * as Option from "./Option.ts"
import * as Order from "./Order.ts"
import type * as Predicate from "./Predicate.ts"
import * as Record from "./Record.ts"
import * as Reducer from "./Reducer.ts"
import * as Result from "./Result.ts"
import * as Tuple from "./Tuple.ts"
import type { NoInfer, TupleOf } from "./Types.ts"
/**
* Reference to the global `Array` constructor.
*
* Use this when you need the native `Array` constructor while the `Array`
* namespace is in scope (e.g. `Array.Array.isArray`, `Array.Array.from`).
*
* **Example** (Using the Array constructor)
*
* ```ts
* import { Array } from "effect"
*
* const arr = new Array.Array(3)
* console.log(arr) // [undefined, undefined, undefined]
* ```
*
* @category constructors
* @since 4.0.0
*/
export const Array = globalThis.Array
/**
* Type lambda for `ReadonlyArray`, used for higher-kinded type operations.
*
* @category type lambdas
* @since 2.0.0
*/
export interface ReadonlyArrayTypeLambda extends TypeLambda {
readonly type: ReadonlyArray
}
/**
* A readonly array guaranteed to have at least one element.
*
* Use this type when you need to ensure non-emptiness at the type level while
* preventing mutation. Many Array module functions accept or return this type.
*
* **Example** (Typing a non-empty array)
*
* ```ts
* import type { Array } from "effect"
*
* const nonEmpty: Array.NonEmptyReadonlyArray = [1, 2, 3]
* const head: number = nonEmpty[0] // guaranteed to exist
* ```
*
* @see {@link NonEmptyArray} — mutable counterpart
* @see {@link isReadonlyArrayNonEmpty} — narrow a `ReadonlyArray` to this type
*
* @category models
* @since 2.0.0
*/
export type NonEmptyReadonlyArray = readonly [A, ...Array]
/**
* A mutable array guaranteed to have at least one element.
*
* This is the mutable counterpart of {@link NonEmptyReadonlyArray}. Most Array
* module functions return `NonEmptyArray` when the result is guaranteed
* non-empty.
*
* **Example** (Typing a mutable non-empty array)
*
* ```ts
* import type { Array } from "effect"
*
* const nonEmpty: Array.NonEmptyArray = [1, 2, 3]
* nonEmpty.push(4)
* ```
*
* @see {@link NonEmptyReadonlyArray} — readonly counterpart
* @see {@link isArrayNonEmpty} — narrow an `Array` to this type
*
* @category models
* @since 2.0.0
*/
export type NonEmptyArray = [A, ...Array]
/**
* Creates a `NonEmptyArray` from one or more elements.
*
* - Use when you have literal values and want a typed non-empty array.
* - The element type is inferred as the union of all arguments.
* - Always returns a `NonEmptyArray` since at least one argument is required.
*
* **Example** (Creating an array from values)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.make(1, 2, 3)
* console.log(result) // [1, 2, 3]
* ```
*
* @see {@link of} — create a single-element array
* @see {@link fromIterable} — create from any iterable
*
* @category constructors
* @since 2.0.0
*/
export const make = >(
...elements: Elements
): NonEmptyArray => elements
/**
* Creates a new `Array` of the specified length with all slots uninitialized.
*
* - Use when you need a pre-sized array and will fill it imperatively.
* - Elements are typed as `A | undefined` since slots are empty.
* - Prefer {@link makeBy} when you can compute each element from its index.
*
* **Example** (Allocating a fixed-size array)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.allocate(3)
* console.log(result.length) // 3
* ```
*
* @see {@link makeBy} — create an array by computing each element
*
* @category constructors
* @since 2.0.0
*/
export const allocate = (n: number): Array => new Array(n)
/**
* Creates a `NonEmptyArray` of length `n` where element `i` is computed by `f(i)`.
*
* - Use when you need an array whose values depend on the index.
* - `n` is normalized to an integer >= 1 — always returns at least one element.
* - Dual: `Array.makeBy(5, f)` or `pipe(5, Array.makeBy(f))`.
*
* **Example** (Generating values from indices)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.makeBy(5, (n) => n * 2)
* console.log(result) // [0, 2, 4, 6, 8]
* ```
*
* @see {@link range} — create a range of integers
* @see {@link replicate} — repeat a single value
*
* @category constructors
* @since 2.0.0
*/
export const makeBy: {
/**
* Creates a `NonEmptyArray` of length `n` where element `i` is computed by `f(i)`.
*
* - Use when you need an array whose values depend on the index.
* - `n` is normalized to an integer >= 1 — always returns at least one element.
* - Dual: `Array.makeBy(5, f)` or `pipe(5, Array.makeBy(f))`.
*
* **Example** (Generating values from indices)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.makeBy(5, (n) => n * 2)
* console.log(result) // [0, 2, 4, 6, 8]
* ```
*
* @see {@link range} — create a range of integers
* @see {@link replicate} — repeat a single value
*
* @category constructors
* @since 2.0.0
*/
(f: (i: number) => A): (n: number) => NonEmptyArray
/**
* Creates a `NonEmptyArray` of length `n` where element `i` is computed by `f(i)`.
*
* - Use when you need an array whose values depend on the index.
* - `n` is normalized to an integer >= 1 — always returns at least one element.
* - Dual: `Array.makeBy(5, f)` or `pipe(5, Array.makeBy(f))`.
*
* **Example** (Generating values from indices)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.makeBy(5, (n) => n * 2)
* console.log(result) // [0, 2, 4, 6, 8]
* ```
*
* @see {@link range} — create a range of integers
* @see {@link replicate} — repeat a single value
*
* @category constructors
* @since 2.0.0
*/
(n: number, f: (i: number) => A): NonEmptyArray
} = dual(2, (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
})
/**
* Creates a `NonEmptyArray` containing a range of integers, inclusive on both
* ends.
*
* - Use when you need a sequence of consecutive integers.
* - If `start > end`, returns `[start]`.
* - Always returns a `NonEmptyArray`.
*
* **Example** (Creating a range)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.range(1, 3)
* console.log(result) // [1, 2, 3]
* ```
*
* @see {@link makeBy} — generate values from a function
*
* @category constructors
* @since 2.0.0
*/
export const range = (start: number, end: number): NonEmptyArray =>
start <= end ? makeBy(end - start + 1, (i) => start + i) : [start]
/**
* Creates a `NonEmptyArray` containing a value repeated `n` times.
*
* - Use when you need multiple copies of the same value.
* - `n` is normalized to an integer >= 1 — always returns at least one element.
* - Dual: `Array.replicate("a", 3)` or `pipe("a", Array.replicate(3))`.
*
* **Example** (Repeating a value)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.replicate("a", 3)
* console.log(result) // ["a", "a", "a"]
* ```
*
* @see {@link makeBy} — vary values based on index
*
* @category constructors
* @since 2.0.0
*/
export const replicate: {
/**
* Creates a `NonEmptyArray` containing a value repeated `n` times.
*
* - Use when you need multiple copies of the same value.
* - `n` is normalized to an integer >= 1 — always returns at least one element.
* - Dual: `Array.replicate("a", 3)` or `pipe("a", Array.replicate(3))`.
*
* **Example** (Repeating a value)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.replicate("a", 3)
* console.log(result) // ["a", "a", "a"]
* ```
*
* @see {@link makeBy} — vary values based on index
*
* @category constructors
* @since 2.0.0
*/
(n: number): (a: A) => NonEmptyArray
/**
* Creates a `NonEmptyArray` containing a value repeated `n` times.
*
* - Use when you need multiple copies of the same value.
* - `n` is normalized to an integer >= 1 — always returns at least one element.
* - Dual: `Array.replicate("a", 3)` or `pipe("a", Array.replicate(3))`.
*
* **Example** (Repeating a value)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.replicate("a", 3)
* console.log(result) // ["a", "a", "a"]
* ```
*
* @see {@link makeBy} — vary values based on index
*
* @category constructors
* @since 2.0.0
*/
(a: A, n: number): NonEmptyArray
} = dual(2, (a: A, n: number): NonEmptyArray => makeBy(n, () => a))
/**
* Converts an `Iterable` to an `Array`.
*
* - If the input is already an array, returns it **by reference** (no copy).
* - Otherwise, creates a new array from the iterable.
* - Use {@link copy} if you need a fresh array even when the input is already
* an array.
*
* **Example** (Converting a Set to an array)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.fromIterable(new Set([1, 2, 3]))
* console.log(result) // [1, 2, 3]
* ```
*
* @see {@link ensure} — wrap a single value or return an existing array
* @see {@link copy} — create a shallow copy of an array
*
* @category constructors
* @since 2.0.0
*/
export const fromIterable = (collection: Iterable): Array =>
Array.isArray(collection) ? collection : Array.from(collection)
/**
* Normalizes a value that is either a single element or an array into an array.
*
* - If the input is already an array, returns it by reference.
* - If the input is a single value, wraps it in a one-element array.
* - Useful for APIs that accept `A | Array`.
*
* **Example** (Normalizing input)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.ensure("a")) // ["a"]
* console.log(Array.ensure(["a", "b", "c"])) // ["a", "b", "c"]
* ```
*
* @see {@link of} — always wrap in a single-element array
* @see {@link fromIterable} — convert any iterable
*
* @category constructors
* @since 3.3.0
*/
export const ensure = (self: ReadonlyArray | A): Array => Array.isArray(self) ? self : [self as A]
/**
* Converts a record into an array of `[key, value]` tuples.
*
* - Key order follows `Object.entries` semantics.
* - Returns an empty array for an empty record.
*
* **Example** (Record to entries)
*
* ```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: (self: Readonly>) => Array<[K, A]> = Record.toEntries
/**
* Converts an `Option` to an array: `Some(a)` becomes `[a]`, `None` becomes `[]`.
*
* **Example** (Option to array)
*
* ```ts
* import { Array, Option } from "effect"
*
* console.log(Array.fromOption(Option.some(1))) // [1]
* console.log(Array.fromOption(Option.none())) // []
* ```
*
* @see {@link getSomes} — extract `Some` values from an array of Options
*
* @category conversions
* @since 2.0.0
*/
export const fromOption: (self: Option.Option) => Array = Option.toArray
/**
* Pattern-matches on an array, handling empty and non-empty cases separately.
*
* - Use when you need to branch on whether an array has elements.
* - `onNonEmpty` receives a `NonEmptyReadonlyArray`.
* - Dual: data-first or data-last.
*
* **Example** (Branching on emptiness)
*
* ```ts
* import { Array } from "effect"
*
* const describe = Array.match({
* onEmpty: () => "empty",
* onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}`
* })
* console.log(describe([])) // "empty"
* console.log(describe([1, 2, 3])) // "head: 1, tail: 2"
* ```
*
* @see {@link matchLeft} — destructures into head + tail
* @see {@link matchRight} — destructures into init + last
*
* @category pattern matching
* @since 2.0.0
*/
export const match: {
/**
* Pattern-matches on an array, handling empty and non-empty cases separately.
*
* - Use when you need to branch on whether an array has elements.
* - `onNonEmpty` receives a `NonEmptyReadonlyArray`.
* - Dual: data-first or data-last.
*
* **Example** (Branching on emptiness)
*
* ```ts
* import { Array } from "effect"
*
* const describe = Array.match({
* onEmpty: () => "empty",
* onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}`
* })
* console.log(describe([])) // "empty"
* console.log(describe([1, 2, 3])) // "head: 1, tail: 2"
* ```
*
* @see {@link matchLeft} — destructures into head + tail
* @see {@link matchRight} — destructures into init + last
*
* @category pattern matching
* @since 2.0.0
*/
(
options: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C
}
): (self: ReadonlyArray) => B | C
/**
* Pattern-matches on an array, handling empty and non-empty cases separately.
*
* - Use when you need to branch on whether an array has elements.
* - `onNonEmpty` receives a `NonEmptyReadonlyArray`.
* - Dual: data-first or data-last.
*
* **Example** (Branching on emptiness)
*
* ```ts
* import { Array } from "effect"
*
* const describe = Array.match({
* onEmpty: () => "empty",
* onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}`
* })
* console.log(describe([])) // "empty"
* console.log(describe([1, 2, 3])) // "head: 1, tail: 2"
* ```
*
* @see {@link matchLeft} — destructures into head + tail
* @see {@link matchRight} — destructures into init + last
*
* @category pattern matching
* @since 2.0.0
*/
(
self: ReadonlyArray,
options: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C
}
): B | C
} = dual(2, (
self: ReadonlyArray,
{ onEmpty, onNonEmpty }: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C
}
): B | C => isReadonlyArrayNonEmpty(self) ? onNonEmpty(self) : onEmpty())
/**
* Pattern-matches on an array from the left, providing the first element and
* the remaining elements separately.
*
* - `onNonEmpty` receives `(head, tail)` where `tail` is the rest of the array.
* - Use when you want to process the first element differently from the rest.
*
* **Example** (Head and tail destructuring)
*
* ```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"
* ```
*
* @see {@link match} — receives the full non-empty array
* @see {@link matchRight} — destructures into init + last
*
* @category pattern matching
* @since 2.0.0
*/
export const matchLeft: {
/**
* Pattern-matches on an array from the left, providing the first element and
* the remaining elements separately.
*
* - `onNonEmpty` receives `(head, tail)` where `tail` is the rest of the array.
* - Use when you want to process the first element differently from the rest.
*
* **Example** (Head and tail destructuring)
*
* ```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"
* ```
*
* @see {@link match} — receives the full non-empty array
* @see {@link matchRight} — destructures into init + last
*
* @category pattern matching
* @since 2.0.0
*/
(
options: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (head: A, tail: Array) => C
}
): (self: ReadonlyArray) => B | C
/**
* Pattern-matches on an array from the left, providing the first element and
* the remaining elements separately.
*
* - `onNonEmpty` receives `(head, tail)` where `tail` is the rest of the array.
* - Use when you want to process the first element differently from the rest.
*
* **Example** (Head and tail destructuring)
*
* ```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"
* ```
*
* @see {@link match} — receives the full non-empty array
* @see {@link matchRight} — destructures into init + last
*
* @category pattern matching
* @since 2.0.0
*/
(
self: ReadonlyArray,
options: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (head: A, tail: Array) => C
}
): B | C
} = dual(2, (
self: ReadonlyArray,
{ onEmpty, onNonEmpty }: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (head: A, tail: Array) => C
}
): B | C => isReadonlyArrayNonEmpty(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty())
/**
* Pattern-matches on an array from the right, providing all elements except the
* last and the last element separately.
*
* - `onNonEmpty` receives `(init, last)` where `init` is everything but the last element.
* - Use when you want to process the last element differently from the rest.
*
* **Example** (Init and last destructuring)
*
* ```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"
* ```
*
* @see {@link match} — receives the full non-empty array
* @see {@link matchLeft} — destructures into head + tail
*
* @category pattern matching
* @since 2.0.0
*/
export const matchRight: {
/**
* Pattern-matches on an array from the right, providing all elements except the
* last and the last element separately.
*
* - `onNonEmpty` receives `(init, last)` where `init` is everything but the last element.
* - Use when you want to process the last element differently from the rest.
*
* **Example** (Init and last destructuring)
*
* ```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"
* ```
*
* @see {@link match} — receives the full non-empty array
* @see {@link matchLeft} — destructures into head + tail
*
* @category pattern matching
* @since 2.0.0
*/
(
options: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (init: Array, last: A) => C
}
): (self: ReadonlyArray) => B | C
/**
* Pattern-matches on an array from the right, providing all elements except the
* last and the last element separately.
*
* - `onNonEmpty` receives `(init, last)` where `init` is everything but the last element.
* - Use when you want to process the last element differently from the rest.
*
* **Example** (Init and last destructuring)
*
* ```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"
* ```
*
* @see {@link match} — receives the full non-empty array
* @see {@link matchLeft} — destructures into head + tail
*
* @category pattern matching
* @since 2.0.0
*/
(
self: ReadonlyArray,
options: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (init: Array, last: A) => C
}
): B | C
} = dual(2, (
self: ReadonlyArray,
{ onEmpty, onNonEmpty }: {
readonly onEmpty: LazyArg
readonly onNonEmpty: (init: Array, last: A) => C
}
): B | C =>
isReadonlyArrayNonEmpty(self) ?
onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) :
onEmpty())
/**
* Adds a single element to the front of an iterable, returning a `NonEmptyArray`.
*
* - Always returns a non-empty array.
* - Does not mutate the input.
*
* **Example** (Prepending an element)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prepend([2, 3, 4], 1)
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link append} — add to the end
* @see {@link prependAll} — prepend multiple elements
*
* @category concatenating
* @since 2.0.0
*/
export const prepend: {
/**
* Adds a single element to the front of an iterable, returning a `NonEmptyArray`.
*
* - Always returns a non-empty array.
* - Does not mutate the input.
*
* **Example** (Prepending an element)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prepend([2, 3, 4], 1)
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link append} — add to the end
* @see {@link prependAll} — prepend multiple elements
*
* @category concatenating
* @since 2.0.0
*/
(head: B): (self: Iterable) => NonEmptyArray
/**
* Adds a single element to the front of an iterable, returning a `NonEmptyArray`.
*
* - Always returns a non-empty array.
* - Does not mutate the input.
*
* **Example** (Prepending an element)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prepend([2, 3, 4], 1)
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link append} — add to the end
* @see {@link prependAll} — prepend multiple elements
*
* @category concatenating
* @since 2.0.0
*/
(self: Iterable, head: B): NonEmptyArray
} = dual(2, (self: Iterable, head: B): NonEmptyArray => [head, ...self])
/**
* Prepends all elements from a prefix iterable to the front of an array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the input.
*
* **Example** (Prepending multiple elements)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prependAll([2, 3], [0, 1])
* console.log(result) // [0, 1, 2, 3]
* ```
*
* @see {@link prepend} — add a single element to the front
* @see {@link appendAll} — add elements to the end
*
* @category concatenating
* @since 2.0.0
*/
export const prependAll: {
/**
* Prepends all elements from a prefix iterable to the front of an array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the input.
*
* **Example** (Prepending multiple elements)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prependAll([2, 3], [0, 1])
* console.log(result) // [0, 1, 2, 3]
* ```
*
* @see {@link prepend} — add a single element to the front
* @see {@link appendAll} — add elements to the end
*
* @category concatenating
* @since 2.0.0
*/
, T extends Iterable>(that: T): (self: S) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer>
/**
* Prepends all elements from a prefix iterable to the front of an array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the input.
*
* **Example** (Prepending multiple elements)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prependAll([2, 3], [0, 1])
* console.log(result) // [0, 1, 2, 3]
* ```
*
* @see {@link prepend} — add a single element to the front
* @see {@link appendAll} — add elements to the end
*
* @category concatenating
* @since 2.0.0
*/
(self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray
/**
* Prepends all elements from a prefix iterable to the front of an array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the input.
*
* **Example** (Prepending multiple elements)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prependAll([2, 3], [0, 1])
* console.log(result) // [0, 1, 2, 3]
* ```
*
* @see {@link prepend} — add a single element to the front
* @see {@link appendAll} — add elements to the end
*
* @category concatenating
* @since 2.0.0
*/
(self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray
/**
* Prepends all elements from a prefix iterable to the front of an array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the input.
*
* **Example** (Prepending multiple elements)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prependAll([2, 3], [0, 1])
* console.log(result) // [0, 1, 2, 3]
* ```
*
* @see {@link prepend} — add a single element to the front
* @see {@link appendAll} — add elements to the end
*
* @category concatenating
* @since 2.0.0
*/
(self: Iterable, that: Iterable): Array
} = dual(
2,
(self: Iterable, that: Iterable): Array => fromIterable(that).concat(fromIterable(self))
)
/**
* Adds a single element to the end of an iterable, returning a `NonEmptyArray`.
*
* - Always returns a non-empty array.
* - Does not mutate the input.
*
* **Example** (Appending an element)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.append([1, 2, 3], 4)
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link prepend} — add to the front
* @see {@link appendAll} — append multiple elements
*
* @category concatenating
* @since 2.0.0
*/
export const append: {
/**
* Adds a single element to the end of an iterable, returning a `NonEmptyArray`.
*
* - Always returns a non-empty array.
* - Does not mutate the input.
*
* **Example** (Appending an element)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.append([1, 2, 3], 4)
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link prepend} — add to the front
* @see {@link appendAll} — append multiple elements
*
* @category concatenating
* @since 2.0.0
*/
(last: B): (self: Iterable) => NonEmptyArray
/**
* Adds a single element to the end of an iterable, returning a `NonEmptyArray`.
*
* - Always returns a non-empty array.
* - Does not mutate the input.
*
* **Example** (Appending an element)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.append([1, 2, 3], 4)
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link prepend} — add to the front
* @see {@link appendAll} — append multiple elements
*
* @category concatenating
* @since 2.0.0
*/
(self: Iterable, last: B): NonEmptyArray
} = dual(2, (self: Iterable, last: B): Array => [...self, last])
/**
* Concatenates two iterables into a single array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the inputs.
*
* **Example** (Concatenating arrays)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.appendAll([1, 2], [3, 4])
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link append} — add a single element to the end
* @see {@link prependAll} — add elements to the front
*
* @category concatenating
* @since 2.0.0
*/
export const appendAll: {
/**
* Concatenates two iterables into a single array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the inputs.
*
* **Example** (Concatenating arrays)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.appendAll([1, 2], [3, 4])
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link append} — add a single element to the end
* @see {@link prependAll} — add elements to the front
*
* @category concatenating
* @since 2.0.0
*/
, T extends Iterable>(that: T): (self: S) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer>
/**
* Concatenates two iterables into a single array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the inputs.
*
* **Example** (Concatenating arrays)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.appendAll([1, 2], [3, 4])
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link append} — add a single element to the end
* @see {@link prependAll} — add elements to the front
*
* @category concatenating
* @since 2.0.0
*/
(self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray
/**
* Concatenates two iterables into a single array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the inputs.
*
* **Example** (Concatenating arrays)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.appendAll([1, 2], [3, 4])
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link append} — add a single element to the end
* @see {@link prependAll} — add elements to the front
*
* @category concatenating
* @since 2.0.0
*/
(self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray
/**
* Concatenates two iterables into a single array.
*
* - If either input is non-empty, the result is a `NonEmptyArray`.
* - Does not mutate the inputs.
*
* **Example** (Concatenating arrays)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.appendAll([1, 2], [3, 4])
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @see {@link append} — add a single element to the end
* @see {@link prependAll} — add elements to the front
*
* @category concatenating
* @since 2.0.0
*/
(self: Iterable, that: Iterable): Array
} = dual(
2,
(self: Iterable, that: Iterable): Array => fromIterable(self).concat(fromIterable(that))
)
/**
* Left-to-right fold that keeps every intermediate accumulator value.
*
* - The output length is `input.length + 1` (starts with the initial value).
* - Always returns a `NonEmptyArray` because the initial value is included.
* - Use {@link reduce} if you only need the final accumulated value.
*
* **Example** (Running totals)
*
* ```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]
* ```
*
* @see {@link scanRight} — right-to-left scan
* @see {@link reduce} — fold without intermediate values
*
* @category folding
* @since 2.0.0
*/
export const scan: {
/**
* Left-to-right fold that keeps every intermediate accumulator value.
*
* - The output length is `input.length + 1` (starts with the initial value).
* - Always returns a `NonEmptyArray` because the initial value is included.
* - Use {@link reduce} if you only need the final accumulated value.
*
* **Example** (Running totals)
*
* ```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]
* ```
*
* @see {@link scanRight} — right-to-left scan
* @see {@link reduce} — fold without intermediate values
*
* @category folding
* @since 2.0.0
*/
(b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray
/**
* Left-to-right fold that keeps every intermediate accumulator value.
*
* - The output length is `input.length + 1` (starts with the initial value).
* - Always returns a `NonEmptyArray` because the initial value is included.
* - Use {@link reduce} if you only need the final accumulated value.
*
* **Example** (Running totals)
*
* ```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]
* ```
*
* @see {@link scanRight} — right-to-left scan
* @see {@link reduce} — fold without intermediate values
*
* @category folding
* @since 2.0.0
*/
(self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray
} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => {
const out: NonEmptyArray = [b]
let i = 0
for (const a of self) {
out[i + 1] = f(out[i], a)
i++
}
return out
})
/**
* Right-to-left fold that keeps every intermediate accumulator value.
*
* - The output length is `input.length + 1` (ends with the initial value).
* - Always returns a `NonEmptyArray`.
*
* **Example** (Reverse running totals)
*
* ```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]
* ```
*
* @see {@link scan} — left-to-right scan
* @see {@link reduceRight} — fold without intermediate values
*
* @category folding
* @since 2.0.0
*/
export const scanRight: {
/**
* Right-to-left fold that keeps every intermediate accumulator value.
*
* - The output length is `input.length + 1` (ends with the initial value).
* - Always returns a `NonEmptyArray`.
*
* **Example** (Reverse running totals)
*
* ```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]
* ```
*
* @see {@link scan} — left-to-right scan
* @see {@link reduceRight} — fold without intermediate values
*
* @category folding
* @since 2.0.0
*/
(b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray
/**
* Right-to-left fold that keeps every intermediate accumulator value.
*
* - The output length is `input.length + 1` (ends with the initial value).
* - Always returns a `NonEmptyArray`.
*
* **Example** (Reverse running totals)
*
* ```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]
* ```
*
* @see {@link scan} — left-to-right scan
* @see {@link reduceRight} — fold without intermediate values
*
* @category folding
* @since 2.0.0
*/
(self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray
} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => {
const input = fromIterable(self)
const out: NonEmptyArray = 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
})
/**
* Tests whether a value is an `Array`.
*
* - Acts as a type guard narrowing the input to `Array`.
* - Delegates to `globalThis.Array.isArray`.
*
* **Example** (Type-guarding an unknown value)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isArray(null)) // false
* console.log(Array.isArray([1, 2, 3])) // true
* ```
*
* @see {@link isArrayEmpty} — check for an empty array
* @see {@link isArrayNonEmpty} — check for a non-empty array
*
* @category guards
* @since 2.0.0
*/
export const isArray: {
/**
* Tests whether a value is an `Array`.
*
* - Acts as a type guard narrowing the input to `Array`.
* - Delegates to `globalThis.Array.isArray`.
*
* **Example** (Type-guarding an unknown value)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isArray(null)) // false
* console.log(Array.isArray([1, 2, 3])) // true
* ```
*
* @see {@link isArrayEmpty} — check for an empty array
* @see {@link isArrayNonEmpty} — check for a non-empty array
*
* @category guards
* @since 2.0.0
*/
(self: unknown): self is Array
/**
* Tests whether a value is an `Array`.
*
* - Acts as a type guard narrowing the input to `Array`.
* - Delegates to `globalThis.Array.isArray`.
*
* **Example** (Type-guarding an unknown value)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isArray(null)) // false
* console.log(Array.isArray([1, 2, 3])) // true
* ```
*
* @see {@link isArrayEmpty} — check for an empty array
* @see {@link isArrayNonEmpty} — check for a non-empty array
*
* @category guards
* @since 2.0.0
*/
(self: T): self is Extract>
} = Array.isArray
/**
* Tests whether a mutable `Array` is empty, narrowing the type to `[]`.
*
* **Example** (Checking for an empty array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isArrayEmpty([])) // true
* console.log(Array.isArrayEmpty([1, 2, 3])) // false
* ```
*
* @see {@link isReadonlyArrayEmpty} — readonly variant
* @see {@link isArrayNonEmpty} — opposite check
*
* @category guards
* @since 2.0.0
*/
export const isArrayEmpty = (self: Array): self is [] => self.length === 0
/**
* Tests whether a `ReadonlyArray` is empty, narrowing the type to `readonly []`.
*
* **Example** (Checking for an empty readonly array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isReadonlyArrayEmpty([])) // true
* console.log(Array.isReadonlyArrayEmpty([1, 2, 3])) // false
* ```
*
* @see {@link isArrayEmpty} — mutable variant
* @see {@link isReadonlyArrayNonEmpty} — opposite check
*
* @category guards
* @since 2.0.0
*/
export const isReadonlyArrayEmpty: (self: ReadonlyArray) => self is readonly [] = isArrayEmpty as any
/**
* Tests whether a mutable `Array` is non-empty, narrowing the type to
* `NonEmptyArray`.
*
* **Example** (Checking for a non-empty array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isArrayNonEmpty([])) // false
* console.log(Array.isArrayNonEmpty([1, 2, 3])) // true
* ```
*
* @see {@link isReadonlyArrayNonEmpty} — readonly variant
* @see {@link isArrayEmpty} — opposite check
*
* @category guards
* @since 2.0.0
*/
export const isArrayNonEmpty: (self: Array) => self is NonEmptyArray = internalArray.isArrayNonEmpty
/**
* Tests whether a `ReadonlyArray` is non-empty, narrowing the type to
* `NonEmptyReadonlyArray`.
*
* **Example** (Checking for a non-empty readonly array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isReadonlyArrayNonEmpty([])) // false
* console.log(Array.isReadonlyArrayNonEmpty([1, 2, 3])) // true
* ```
*
* @see {@link isArrayNonEmpty} — mutable variant
* @see {@link isReadonlyArrayEmpty} — opposite check
*
* @category guards
* @since 2.0.0
*/
export const isReadonlyArrayNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray =
internalArray.isArrayNonEmpty
/**
* Returns the number of elements in a `ReadonlyArray`.
*
* **Example** (Getting the length)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.length([1, 2, 3])) // 3
* ```
*
* @category getters
* @since 2.0.0
*/
export const length = (self: ReadonlyArray): number => self.length
/** @internal */
export function isOutOfBounds(i: number, as: ReadonlyArray): boolean {
return i < 0 || i >= as.length
}
const clamp = (i: number, as: ReadonlyArray): number => Math.floor(Math.min(Math.max(0, i), as.length))
/**
* Safely reads an element at the given index, returning `Option.some` or
* `Option.none` if the index is out of bounds.
*
* - The index is floored to an integer.
* - Never throws.
*
* **Example** (Safe index access)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.get([1, 2, 3], 1)) // Some(2)
* console.log(Array.get([1, 2, 3], 10)) // None
* ```
*
* @see {@link getUnsafe} — throws on out of bounds
* @see {@link head} — get the first element
* @see {@link last} — get the last element
*
* @category getters
* @since 2.0.0
*/
export const get: {
/**
* Safely reads an element at the given index, returning `Option.some` or
* `Option.none` if the index is out of bounds.
*
* - The index is floored to an integer.
* - Never throws.
*
* **Example** (Safe index access)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.get([1, 2, 3], 1)) // Some(2)
* console.log(Array.get([1, 2, 3], 10)) // None
* ```
*
* @see {@link getUnsafe} — throws on out of bounds
* @see {@link head} — get the first element
* @see {@link last} — get the last element
*
* @category getters
* @since 2.0.0
*/
(index: number): (self: ReadonlyArray) => Option.Option
/**
* Safely reads an element at the given index, returning `Option.some` or
* `Option.none` if the index is out of bounds.
*
* - The index is floored to an integer.
* - Never throws.
*
* **Example** (Safe index access)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.get([1, 2, 3], 1)) // Some(2)
* console.log(Array.get([1, 2, 3], 10)) // None
* ```
*
* @see {@link getUnsafe} — throws on out of bounds
* @see {@link head} — get the first element
* @see {@link last} — get the last element
*
* @category getters
* @since 2.0.0
*/
(self: ReadonlyArray, index: number): Option.Option
} = dual(2, (self: ReadonlyArray, index: number): Option.Option => {
const i = Math.floor(index)
return isOutOfBounds(i, self) ? Option.none() : Option.some(self[i])
})
/**
* Reads an element at the given index, throwing if the index is out of bounds.
*
* - Throws an `Error` with the message `"Index out of bounds: "`.
* - Prefer {@link get} for safe access.
*
* **Example** (Unsafe index access)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.getUnsafe([1, 2, 3], 1)) // 2
* // Array.getUnsafe([1, 2, 3], 10) // throws Error
* ```
*
* @see {@link get} — safe version returning `Option`
*
* @since 2.0.0
* @category unsafe
*/
export const getUnsafe: {
/**
* Reads an element at the given index, throwing if the index is out of bounds.
*
* - Throws an `Error` with the message `"Index out of bounds: "`.
* - Prefer {@link get} for safe access.
*
* **Example** (Unsafe index access)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.getUnsafe([1, 2, 3], 1)) // 2
* // Array.getUnsafe([1, 2, 3], 10) // throws Error
* ```
*
* @see {@link get} — safe version returning `Option`
*
* @since 2.0.0
* @category unsafe
*/
(index: number): (self: ReadonlyArray) => A
/**
* Reads an element at the given index, throwing if the index is out of bounds.
*
* - Throws an `Error` with the message `"Index out of bounds: "`.
* - Prefer {@link get} for safe access.
*
* **Example** (Unsafe index access)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.getUnsafe([1, 2, 3], 1)) // 2
* // Array.getUnsafe([1, 2, 3], 10) // throws Error
* ```
*
* @see {@link get} — safe version returning `Option`
*
* @since 2.0.0
* @category unsafe
*/
(self: ReadonlyArray, index: number): A
} = dual(2, (self: ReadonlyArray, index: number): A => {
const i = Math.floor(index)
if (isOutOfBounds(i, self)) {
throw new Error(`Index out of bounds: ${i}`)
}
return self[i]
})
/**
* Splits a non-empty array into its first element and the remaining elements.
*
* - Returns a tuple `[head, tail]`.
* - Requires a `NonEmptyReadonlyArray`.
*
* **Example** (Destructuring head and tail)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.unprepend([1, 2, 3, 4])
* console.log(result) // [1, [2, 3, 4]]
* ```
*
* @see {@link unappend} — split into init + last
* @see {@link headNonEmpty} — get only the head
* @see {@link tailNonEmpty} — get only the tail
*
* @category splitting
* @since 2.0.0
*/
export const unprepend = (
self: NonEmptyReadonlyArray
): [firstElement: A, remainingElements: Array] => [headNonEmpty(self), tailNonEmpty(self)]
/**
* Splits a non-empty array into all elements except the last, and the last
* element.
*
* - Returns a tuple `[init, last]`.
* - Requires a `NonEmptyReadonlyArray`.
*
* **Example** (Destructuring init and last)
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.unappend([1, 2, 3, 4])
* console.log(result) // [[1, 2, 3], 4]
* ```
*
* @see {@link unprepend} — split into head + tail
* @see {@link initNonEmpty} — get only the init
* @see {@link lastNonEmpty} — get only the last
*
* @category splitting
* @since 2.0.0
*/
export const unappend = (
self: NonEmptyReadonlyArray
): [arrayWithoutLastElement: Array, lastElement: A] => [initNonEmpty(self), lastNonEmpty(self)]
/**
* Returns the first element of an array wrapped in `Option.some`, or
* `Option.none` if the array is empty.
*
* **Example** (Getting the first element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.head([1, 2, 3])) // Some(1)
* console.log(Array.head([])) // None
* ```
*
* @see {@link headNonEmpty} — direct access when array is known non-empty
* @see {@link last} — get the last element
*
* @category getters
* @since 2.0.0
*/
export const head: (self: ReadonlyArray) => Option.Option = get(0)
/**
* Returns the first element of a `NonEmptyReadonlyArray` directly (no `Option`
* wrapper).
*
* **Example** (Getting the head of a non-empty array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.headNonEmpty([1, 2, 3, 4])) // 1
* ```
*
* @see {@link head} — safe version for possibly-empty arrays
*
* @category getters
* @since 2.0.0
*/
export const headNonEmpty: (self: NonEmptyReadonlyArray) => A = getUnsafe(0)
/**
* Returns the last element of an array wrapped in `Option.some`, or
* `Option.none` if the array is empty.
*
* **Example** (Getting the last element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.last([1, 2, 3])) // Some(3)
* console.log(Array.last([])) // None
* ```
*
* @see {@link lastNonEmpty} — direct access when array is known non-empty
* @see {@link head} — get the first element
*
* @category getters
* @since 2.0.0
*/
export const last = (self: ReadonlyArray): Option.Option =>
isReadonlyArrayNonEmpty(self) ? Option.some(lastNonEmpty(self)) : Option.none()
/**
* Returns the last element of a `NonEmptyReadonlyArray` directly (no `Option`
* wrapper).
*
* **Example** (Getting the last of a non-empty array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.lastNonEmpty([1, 2, 3, 4])) // 4
* ```
*
* @see {@link last} — safe version for possibly-empty arrays
*
* @category getters
* @since 2.0.0
*/
export const lastNonEmpty = (self: NonEmptyReadonlyArray): A => self[self.length - 1]
/**
* Returns all elements except the first, wrapped in an `Option`.
*
* - Allocates a new array via `slice(1)`.
* - Returns `Option.none()` for empty inputs.
*
* **Example** (Getting the tail)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.tail([1, 2, 3, 4])) // Option.some([2, 3, 4])
* console.log(Array.tail([])) // Option.none()
* ```
*
* @see {@link tailNonEmpty} — when the array is known non-empty
* @see {@link init} — all elements except the last
*
* @category getters
* @since 2.0.0
*/
export function tail(self: Iterable): Option.Option> {
const as = fromIterable(self)
return isReadonlyArrayNonEmpty(as) ? Option.some(tailNonEmpty(as)) : Option.none()
}
/**
* Returns all elements except the first of a `NonEmptyReadonlyArray`.
*
* **Example** (Getting the tail of a non-empty array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.tailNonEmpty([1, 2, 3, 4])) // [2, 3, 4]
* ```
*
* @see {@link tail} — safe version for possibly-empty arrays
* @see {@link initNonEmpty} — all elements except the last
*
* @category getters
* @since 2.0.0
*/
export const tailNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(1)
/**
* Returns all elements except the last, wrapped in an `Option`.
*
* - Allocates a new array via `slice(0, -1)`.
* - Returns `Option.none()` for empty inputs.
*
* **Example** (Getting init)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.init([1, 2, 3, 4])) // Option.some([1, 2, 3])
* console.log(Array.init([])) // Option.none()
* ```
*
* @see {@link initNonEmpty} — when the array is known non-empty
* @see {@link tail} — all elements except the first
*
* @category getters
* @since 2.0.0
*/
export function init(self: Iterable): Option.Option> {
const as = fromIterable(self)
return isReadonlyArrayNonEmpty(as) ? Option.some(initNonEmpty(as)) : Option.none()
}
/**
* Returns all elements except the last of a `NonEmptyReadonlyArray`.
*
* **Example** (Getting init of a non-empty array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.initNonEmpty([1, 2, 3, 4])) // [1, 2, 3]
* ```
*
* @see {@link init} — safe version for possibly-empty arrays
* @see {@link tailNonEmpty} — all elements except the first
*
* @category getters
* @since 2.0.0
*/
export const initNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(0, -1)
/**
* Keeps the first `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns an empty array when `n <= 0`.
*
* **Example** (Taking from the start)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.take([1, 2, 3, 4, 5], 3)) // [1, 2, 3]
* ```
*
* @see {@link takeRight} — keep from the end
* @see {@link takeWhile} — keep while predicate holds
* @see {@link drop} — remove from the start
*
* @category getters
* @since 2.0.0
*/
export const take: {
/**
* Keeps the first `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns an empty array when `n <= 0`.
*
* **Example** (Taking from the start)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.take([1, 2, 3, 4, 5], 3)) // [1, 2, 3]
* ```
*
* @see {@link takeRight} — keep from the end
* @see {@link takeWhile} — keep while predicate holds
* @see {@link drop} — remove from the start
*
* @category getters
* @since 2.0.0
*/
(n: number): (self: Iterable) => Array
/**
* Keeps the first `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns an empty array when `n <= 0`.
*
* **Example** (Taking from the start)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.take([1, 2, 3, 4, 5], 3)) // [1, 2, 3]
* ```
*
* @see {@link takeRight} — keep from the end
* @see {@link takeWhile} — keep while predicate holds
* @see {@link drop} — remove from the start
*
* @category getters
* @since 2.0.0
*/
(self: Iterable, n: number): Array
} = dual(2, (self: Iterable, n: number): Array => {
const input = fromIterable(self)
return input.slice(0, clamp(n, input))
})
/**
* Keeps the last `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns an empty array when `n <= 0`.
*
* **Example** (Taking from the end)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.takeRight([1, 2, 3, 4, 5], 3)) // [3, 4, 5]
* ```
*
* @see {@link take} — keep from the start
* @see {@link dropRight} — remove from the end
*
* @category getters
* @since 2.0.0
*/
export const takeRight: {
/**
* Keeps the last `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns an empty array when `n <= 0`.
*
* **Example** (Taking from the end)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.takeRight([1, 2, 3, 4, 5], 3)) // [3, 4, 5]
* ```
*
* @see {@link take} — keep from the start
* @see {@link dropRight} — remove from the end
*
* @category getters
* @since 2.0.0
*/
(n: number): (self: Iterable) => Array
/**
* Keeps the last `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns an empty array when `n <= 0`.
*
* **Example** (Taking from the end)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.takeRight([1, 2, 3, 4, 5], 3)) // [3, 4, 5]
* ```
*
* @see {@link take} — keep from the start
* @see {@link dropRight} — remove from the end
*
* @category getters
* @since 2.0.0
*/
(self: Iterable, n: number): Array
} = dual(2, (self: Iterable, n: number): Array => {
const input = fromIterable(self)
const i = clamp(n, input)
return i === 0 ? [] : input.slice(-i)
})
/**
* Takes elements from the start while the predicate holds, stopping at the
* first element that fails.
*
* - Supports refinements for type narrowing.
* - The predicate receives `(element, index)`.
*
* **Example** (Taking while condition holds)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.takeWhile([1, 3, 2, 4, 1, 2], (x) => x < 4)) // [1, 3, 2]
* ```
*
* @see {@link take} — take a fixed count
* @see {@link dropWhile} — drop while predicate holds
* @see {@link span} — split into matching prefix + rest
*
* @category getters
* @since 2.0.0
*/
export const takeWhile: {
/**
* Takes elements from the start while the predicate holds, stopping at the
* first element that fails.
*
* - Supports refinements for type narrowing.
* - The predicate receives `(element, index)`.
*
* **Example** (Taking while condition holds)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.takeWhile([1, 3, 2, 4, 1, 2], (x) => x < 4)) // [1, 3, 2]
* ```
*
* @see {@link take} — take a fixed count
* @see {@link dropWhile} — drop while predicate holds
* @see {@link span} — split into matching prefix + rest
*
* @category getters
* @since 2.0.0
*/
(refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Array
/**
* Takes elements from the start while the predicate holds, stopping at the
* first element that fails.
*
* - Supports refinements for type narrowing.
* - The predicate receives `(element, index)`.
*
* **Example** (Taking while condition holds)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.takeWhile([1, 3, 2, 4, 1, 2], (x) => x < 4)) // [1, 3, 2]
* ```
*
* @see {@link take} — take a fixed count
* @see {@link dropWhile} — drop while predicate holds
* @see {@link span} — split into matching prefix + rest
*
* @category getters
* @since 2.0.0
*/
(predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Array
/**
* Takes elements from the start while the predicate holds, stopping at the
* first element that fails.
*
* - Supports refinements for type narrowing.
* - The predicate receives `(element, index)`.
*
* **Example** (Taking while condition holds)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.takeWhile([1, 3, 2, 4, 1, 2], (x) => x < 4)) // [1, 3, 2]
* ```
*
* @see {@link take} — take a fixed count
* @see {@link dropWhile} — drop while predicate holds
* @see {@link span} — split into matching prefix + rest
*
* @category getters
* @since 2.0.0
*/
(self: Iterable, refinement: (a: A, i: number) => a is B): Array
/**
* Takes elements from the start while the predicate holds, stopping at the
* first element that fails.
*
* - Supports refinements for type narrowing.
* - The predicate receives `(element, index)`.
*
* **Example** (Taking while condition holds)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.takeWhile([1, 3, 2, 4, 1, 2], (x) => x < 4)) // [1, 3, 2]
* ```
*
* @see {@link take} — take a fixed count
* @see {@link dropWhile} — drop while predicate holds
* @see {@link span} — split into matching prefix + rest
*
* @category getters
* @since 2.0.0
*/
(self: Iterable, predicate: (a: A, i: number) => boolean): Array
} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Array => {
let i = 0
const out: Array = []
for (const a of self) {
if (!predicate(a, i)) {
break
}
out.push(a)
i++
}
return out
})
/**
* Takes elements from the start while a `Filter` succeeds, collecting transformed values.
*
* - The filter receives `(element, index)`.
* - Stops at the first filter failure.
*
* @category getters
* @since 4.0.0
*/
export const takeWhileFilter: {
/**
* Takes elements from the start while a `Filter` succeeds, collecting transformed values.
*
* - The filter receives `(element, index)`.
* - Stops at the first filter failure.
*
* @category getters
* @since 4.0.0
*/
(f: (input: NoInfer, i: number) => Result.Result): (self: Iterable) => Array
/**
* Takes elements from the start while a `Filter` succeeds, collecting transformed values.
*
* - The filter receives `(element, index)`.
* - Stops at the first filter failure.
*
* @category getters
* @since 4.0.0
*/
(
self: Iterable,
f: (input: NoInfer, i: number) => Result.Result
): Array
} = dual(2, (self: Iterable, f: (input: NoInfer, i: number) => Result.Result): Array => {
let i = 0
const out: Array = []
for (const a of self) {
const result = f(a, i)
if (Result.isFailure(result)) {
break
}
out.push(result.success)
i++
}
return out
})
const spanIndex = (self: Iterable, predicate: (a: A, i: number) => boolean): number => {
let i = 0
for (const a of self) {
if (!predicate(a, i)) {
break
}
i++
}
return i
}
/**
* Splits an iterable into two arrays: the longest prefix where the predicate
* holds, and the remaining elements.
*
* - Equivalent to `[takeWhile(pred), dropWhile(pred)]` but more efficient
* (single pass).
* - Supports refinements for type narrowing of the prefix.
*
* **Example** (Splitting at predicate boundary)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.span([1, 3, 2, 4, 5], (x) => x % 2 === 1)) // [[1, 3], [2, 4, 5]]
* ```
*
* @see {@link takeWhile} — keep only the matching prefix
* @see {@link dropWhile} — keep only the rest
* @see {@link splitWhere} — split at the first element matching a predicate
*
* @category splitting
* @since 2.0.0
*/
export const span: {
/**
* Splits an iterable into two arrays: the longest prefix where the predicate
* holds, and the remaining elements.
*
* - Equivalent to `[takeWhile(pred), dropWhile(pred)]` but more efficient
* (single pass).
* - Supports refinements for type narrowing of the prefix.
*
* **Example** (Splitting at predicate boundary)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.span([1, 3, 2, 4, 5], (x) => x % 2 === 1)) // [[1, 3], [2, 4, 5]]
* ```
*
* @see {@link takeWhile} — keep only the matching prefix
* @see {@link dropWhile} — keep only the rest
* @see {@link splitWhere} — split at the first element matching a predicate
*
* @category splitting
* @since 2.0.0
*/
(refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => [init: Array, rest: Array>]
/**
* Splits an iterable into two arrays: the longest prefix where the predicate
* holds, and the remaining elements.
*
* - Equivalent to `[takeWhile(pred), dropWhile(pred)]` but more efficient
* (single pass).
* - Supports refinements for type narrowing of the prefix.
*
* **Example** (Splitting at predicate boundary)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.span([1, 3, 2, 4, 5], (x) => x % 2 === 1)) // [[1, 3], [2, 4, 5]]
* ```
*
* @see {@link takeWhile} — keep only the matching prefix
* @see {@link dropWhile} — keep only the rest
* @see {@link splitWhere} — split at the first element matching a predicate
*
* @category splitting
* @since 2.0.0
*/
(predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => [init: Array, rest: Array]
/**
* Splits an iterable into two arrays: the longest prefix where the predicate
* holds, and the remaining elements.
*
* - Equivalent to `[takeWhile(pred), dropWhile(pred)]` but more efficient
* (single pass).
* - Supports refinements for type narrowing of the prefix.
*
* **Example** (Splitting at predicate boundary)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.span([1, 3, 2, 4, 5], (x) => x % 2 === 1)) // [[1, 3], [2, 4, 5]]
* ```
*
* @see {@link takeWhile} — keep only the matching prefix
* @see {@link dropWhile} — keep only the rest
* @see {@link splitWhere} — split at the first element matching a predicate
*
* @category splitting
* @since 2.0.0
*/
(self: Iterable, refinement: (a: A, i: number) => a is B): [init: Array, rest: Array>]
/**
* Splits an iterable into two arrays: the longest prefix where the predicate
* holds, and the remaining elements.
*
* - Equivalent to `[takeWhile(pred), dropWhile(pred)]` but more efficient
* (single pass).
* - Supports refinements for type narrowing of the prefix.
*
* **Example** (Splitting at predicate boundary)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.span([1, 3, 2, 4, 5], (x) => x % 2 === 1)) // [[1, 3], [2, 4, 5]]
* ```
*
* @see {@link takeWhile} — keep only the matching prefix
* @see {@link dropWhile} — keep only the rest
* @see {@link splitWhere} — split at the first element matching a predicate
*
* @category splitting
* @since 2.0.0
*/
(self: Iterable, predicate: (a: A, i: number) => boolean): [init: Array, rest: Array]
} = dual(
2,
(self: Iterable, predicate: (a: A, i: number) => boolean): [init: Array, rest: Array] => {
const input = fromIterable(self)
return splitAt(input, spanIndex(input, predicate))
}
)
/**
* Removes the first `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns a copy of the full array when `n <= 0`.
*
* **Example** (Dropping from the start)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.drop([1, 2, 3, 4, 5], 2)) // [3, 4, 5]
* ```
*
* @see {@link dropRight} — remove from the end
* @see {@link dropWhile} — remove while predicate holds
* @see {@link take} — keep from the start
*
* @category getters
* @since 2.0.0
*/
export const drop: {
/**
* Removes the first `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns a copy of the full array when `n <= 0`.
*
* **Example** (Dropping from the start)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.drop([1, 2, 3, 4, 5], 2)) // [3, 4, 5]
* ```
*
* @see {@link dropRight} — remove from the end
* @see {@link dropWhile} — remove while predicate holds
* @see {@link take} — keep from the start
*
* @category getters
* @since 2.0.0
*/
(n: number): (self: Iterable) => Array
/**
* Removes the first `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
* - Returns a copy of the full array when `n <= 0`.
*
* **Example** (Dropping from the start)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.drop([1, 2, 3, 4, 5], 2)) // [3, 4, 5]
* ```
*
* @see {@link dropRight} — remove from the end
* @see {@link dropWhile} — remove while predicate holds
* @see {@link take} — keep from the start
*
* @category getters
* @since 2.0.0
*/
(self: Iterable, n: number): Array
} = dual(2, (self: Iterable, n: number): Array => {
const input = fromIterable(self)
return input.slice(clamp(n, input), input.length)
})
/**
* Removes the last `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
*
* **Example** (Dropping from the end)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.dropRight([1, 2, 3, 4, 5], 2)) // [1, 2, 3]
* ```
*
* @see {@link drop} — remove from the start
* @see {@link takeRight} — keep from the end
*
* @category getters
* @since 2.0.0
*/
export const dropRight: {
/**
* Removes the last `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
*
* **Example** (Dropping from the end)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.dropRight([1, 2, 3, 4, 5], 2)) // [1, 2, 3]
* ```
*
* @see {@link drop} — remove from the start
* @see {@link takeRight} — keep from the end
*
* @category getters
* @since 2.0.0
*/
(n: number): (self: Iterable) => Array
/**
* Removes the last `n` elements, creating a new array.
*
* - `n` is clamped to `[0, length]`.
*
* **Example** (Dropping from the end)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.dropRight([1, 2, 3, 4, 5], 2)) // [1, 2, 3]
* ```
*
* @see {@link drop} — remove from the start
* @see {@link takeRight} — keep from the end
*
* @category getters
* @since 2.0.0
*/
(self: Iterable, n: number): Array
} = dual(2, (self: Iterable, n: number): Array => {
const input = fromIterable(self)
return input.slice(0, input.length - clamp(n, input))
})
/**
* Drops elements from the start while the predicate holds, returning the rest.
*
* - The predicate receives `(element, index)`.
*
* **Example** (Dropping while condition holds)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.dropWhile([1, 2, 3, 4, 5], (x) => x < 4)) // [4, 5]
* ```
*
* @see {@link takeWhile} — keep the matching prefix instead
* @see {@link drop} — drop a fixed count
*
* @category getters
* @since 2.0.0
*/
export const dropWhile: {
/**
* Drops elements from the start while the predicate holds, returning the rest.
*
* - The predicate receives `(element, index)`.
*
* **Example** (Dropping while condition holds)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.dropWhile([1, 2, 3, 4, 5], (x) => x < 4)) // [4, 5]
* ```
*
* @see {@link takeWhile} — keep the matching prefix instead
* @see {@link drop} — drop a fixed count
*
* @category getters
* @since 2.0.0
*/
(predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Array
/**
* Drops elements from the start while the predicate holds, returning the rest.
*
* - The predicate receives `(element, index)`.
*
* **Example** (Dropping while condition holds)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.dropWhile([1, 2, 3, 4, 5], (x) => x < 4)) // [4, 5]
* ```
*
* @see {@link takeWhile} — keep the matching prefix instead
* @see {@link drop} — drop a fixed count
*
* @category getters
* @since 2.0.0
*/
(self: Iterable, predicate: (a: A, i: number) => boolean): Array
} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Array => {
const input = fromIterable(self)
let i = 0
while (i < input.length) {
if (!predicate(input[i], i)) {
break
}
i++
}
return input.slice(i)
})
/**
* Drops elements from the start while a `Filter` succeeds.
*
* - The filter receives `(element, index)`.
* - Returns the remaining original elements after the first filter failure.
*
* @category getters
* @since 4.0.0
*/
export const dropWhileFilter: {
/**
* Drops elements from the start while a `Filter` succeeds.
*
* - The filter receives `(element, index)`.
* - Returns the remaining original elements after the first filter failure.
*
* @category getters
* @since 4.0.0
*/
(f: (input: NoInfer, i: number) => Result.Result): (self: Iterable) => Array
/**
* Drops elements from the start while a `Filter` succeeds.
*
* - The filter receives `(element, index)`.
* - Returns the remaining original elements after the first filter failure.
*
* @category getters
* @since 4.0.0
*/
(self: Iterable, f: (input: A, i: number) => Result.Result): Array
} = dual(
2,
(self: Iterable, f: (input: A, i: number) => Result.Result): Array => {
const input = fromIterable(self)
let i = 0
while (i < input.length) {
if (Result.isFailure(f(input[i], i))) {
break
}
i++
}
return input.slice(i)
}
)
/**
* Returns the index of the first element matching the predicate, wrapped in an
* `Option`.
*
* **Example** (Finding an index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstIndex([5, 3, 8, 9], (x) => x > 5)) // Option.some(2)
* ```
*
* @see {@link findLastIndex} — search from the end
* @see {@link findFirst} — get the element itself
*
* @category elements
* @since 2.0.0
*/
export const findFirstIndex: {
/**
* Returns the index of the first element matching the predicate, wrapped in an
* `Option`.
*
* **Example** (Finding an index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstIndex([5, 3, 8, 9], (x) => x > 5)) // Option.some(2)
* ```
*
* @see {@link findLastIndex} — search from the end
* @see {@link findFirst} — get the element itself
*
* @category elements
* @since 2.0.0
*/
(predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option
/**
* Returns the index of the first element matching the predicate, wrapped in an
* `Option`.
*
* **Example** (Finding an index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstIndex([5, 3, 8, 9], (x) => x > 5)) // Option.some(2)
* ```
*
* @see {@link findLastIndex} — search from the end
* @see {@link findFirst} — get the element itself
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option
} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option => {
let i = 0
for (const a of self) {
if (predicate(a, i)) {
return Option.some(i)
}
i++
}
return Option.none()
})
/**
* Returns the index of the last element matching the predicate, wrapped in an
* `Option`.
*
* **Example** (Finding the last matching index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLastIndex([1, 3, 8, 9], (x) => x < 5)) // Option.some(1)
* ```
*
* @see {@link findFirstIndex} — search from the start
* @see {@link findLast} — get the element itself
*
* @category elements
* @since 2.0.0
*/
export const findLastIndex: {
/**
* Returns the index of the last element matching the predicate, wrapped in an
* `Option`.
*
* **Example** (Finding the last matching index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLastIndex([1, 3, 8, 9], (x) => x < 5)) // Option.some(1)
* ```
*
* @see {@link findFirstIndex} — search from the start
* @see {@link findLast} — get the element itself
*
* @category elements
* @since 2.0.0
*/
(predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option
/**
* Returns the index of the last element matching the predicate, wrapped in an
* `Option`.
*
* **Example** (Finding the last matching index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLastIndex([1, 3, 8, 9], (x) => x < 5)) // Option.some(1)
* ```
*
* @see {@link findFirstIndex} — search from the start
* @see {@link findLast} — get the element itself
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option
} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option => {
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 matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Accepts a predicate `(a, i) => boolean`, a refinement, or a function
* `(a, i) => Option` for simultaneous find-and-transform.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the first match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some(4)
* ```
*
* @see {@link findLast} — search from the end
* @see {@link findFirstIndex} — get the index instead
* @see {@link findFirstWithIndex} — get both element and index
*
* @category elements
* @since 2.0.0
*/
export const findFirst: {
/**
* Returns the first element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Accepts a predicate `(a, i) => boolean`, a refinement, or a function
* `(a, i) => Option` for simultaneous find-and-transform.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the first match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some(4)
* ```
*
* @see {@link findLast} — search from the end
* @see {@link findFirstIndex} — get the index instead
* @see {@link findFirstWithIndex} — get both element and index
*
* @category elements
* @since 2.0.0
*/
(f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option
/**
* Returns the first element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Accepts a predicate `(a, i) => boolean`, a refinement, or a function
* `(a, i) => Option` for simultaneous find-and-transform.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the first match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some(4)
* ```
*
* @see {@link findLast} — search from the end
* @see {@link findFirstIndex} — get the index instead
* @see {@link findFirstWithIndex} — get both element and index
*
* @category elements
* @since 2.0.0
*/
(refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option
/**
* Returns the first element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Accepts a predicate `(a, i) => boolean`, a refinement, or a function
* `(a, i) => Option` for simultaneous find-and-transform.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the first match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some(4)
* ```
*
* @see {@link findLast} — search from the end
* @see {@link findFirstIndex} — get the index instead
* @see {@link findFirstWithIndex} — get both element and index
*
* @category elements
* @since 2.0.0
*/
(predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option
/**
* Returns the first element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Accepts a predicate `(a, i) => boolean`, a refinement, or a function
* `(a, i) => Option` for simultaneous find-and-transform.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the first match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some(4)
* ```
*
* @see {@link findLast} — search from the end
* @see {@link findFirstIndex} — get the index instead
* @see {@link findFirstWithIndex} — get both element and index
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option
/**
* Returns the first element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Accepts a predicate `(a, i) => boolean`, a refinement, or a function
* `(a, i) => Option` for simultaneous find-and-transform.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the first match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some(4)
* ```
*
* @see {@link findLast} — search from the end
* @see {@link findFirstIndex} — get the index instead
* @see {@link findFirstWithIndex} — get both element and index
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option
/**
* Returns the first element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Accepts a predicate `(a, i) => boolean`, a refinement, or a function
* `(a, i) => Option` for simultaneous find-and-transform.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the first match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some(4)
* ```
*
* @see {@link findLast} — search from the end
* @see {@link findFirstIndex} — get the index instead
* @see {@link findFirstWithIndex} — get both element and index
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option
} = moduleIterable.findFirst
/**
* Returns a tuple `[element, index]` of the first element matching a
* predicate, wrapped in an `Option`.
*
* **Example** (Finding element with its index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some([4, 3])
* ```
*
* @see {@link findFirst} — get only the element
* @see {@link findFirstIndex} — get only the index
*
* @category elements
* @since 3.17.0
*/
export const findFirstWithIndex: {
/**
* Returns a tuple `[element, index]` of the first element matching a
* predicate, wrapped in an `Option`.
*
* **Example** (Finding element with its index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some([4, 3])
* ```
*
* @see {@link findFirst} — get only the element
* @see {@link findFirstIndex} — get only the index
*
* @category elements
* @since 3.17.0
*/
(f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option<[B, number]>
/**
* Returns a tuple `[element, index]` of the first element matching a
* predicate, wrapped in an `Option`.
*
* **Example** (Finding element with its index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some([4, 3])
* ```
*
* @see {@link findFirst} — get only the element
* @see {@link findFirstIndex} — get only the index
*
* @category elements
* @since 3.17.0
*/
(refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option<[B, number]>
/**
* Returns a tuple `[element, index]` of the first element matching a
* predicate, wrapped in an `Option`.
*
* **Example** (Finding element with its index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some([4, 3])
* ```
*
* @see {@link findFirst} — get only the element
* @see {@link findFirstIndex} — get only the index
*
* @category elements
* @since 3.17.0
*/
(predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option<[A, number]>
/**
* Returns a tuple `[element, index]` of the first element matching a
* predicate, wrapped in an `Option`.
*
* **Example** (Finding element with its index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some([4, 3])
* ```
*
* @see {@link findFirst} — get only the element
* @see {@link findFirstIndex} — get only the index
*
* @category elements
* @since 3.17.0
*/
(self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option<[B, number]>
/**
* Returns a tuple `[element, index]` of the first element matching a
* predicate, wrapped in an `Option`.
*
* **Example** (Finding element with its index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some([4, 3])
* ```
*
* @see {@link findFirst} — get only the element
* @see {@link findFirstIndex} — get only the index
*
* @category elements
* @since 3.17.0
*/
(self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option<[B, number]>
/**
* Returns a tuple `[element, index]` of the first element matching a
* predicate, wrapped in an `Option`.
*
* **Example** (Finding element with its index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3)) // Option.some([4, 3])
* ```
*
* @see {@link findFirst} — get only the element
* @see {@link findFirstIndex} — get only the index
*
* @category elements
* @since 3.17.0
*/
(self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option<[A, number]>
} = dual(
2,
(
self: Iterable,
f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option.Option)
): Option.Option<[A, number]> => {
let i = 0
for (const a of self) {
const o = f(a, i)
if (typeof o === "boolean") {
if (o) {
return Option.some([a, i])
}
} else {
if (Option.isSome(o)) {
return Option.some([o.value, i])
}
}
i++
}
return Option.none()
}
)
/**
* Returns the last element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Searches from the end of the array.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the last match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0)) // Option.some(4)
* ```
*
* @see {@link findFirst} — search from the start
* @see {@link findLastIndex} — get the index instead
*
* @category elements
* @since 2.0.0
*/
export const findLast: {
/**
* Returns the last element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Searches from the end of the array.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the last match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0)) // Option.some(4)
* ```
*
* @see {@link findFirst} — search from the start
* @see {@link findLastIndex} — get the index instead
*
* @category elements
* @since 2.0.0
*/
(f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option
/**
* Returns the last element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Searches from the end of the array.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the last match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0)) // Option.some(4)
* ```
*
* @see {@link findFirst} — search from the start
* @see {@link findLastIndex} — get the index instead
*
* @category elements
* @since 2.0.0
*/
(refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option
/**
* Returns the last element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Searches from the end of the array.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the last match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0)) // Option.some(4)
* ```
*
* @see {@link findFirst} — search from the start
* @see {@link findLastIndex} — get the index instead
*
* @category elements
* @since 2.0.0
*/
(predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option
/**
* Returns the last element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Searches from the end of the array.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the last match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0)) // Option.some(4)
* ```
*
* @see {@link findFirst} — search from the start
* @see {@link findLastIndex} — get the index instead
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option
/**
* Returns the last element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Searches from the end of the array.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the last match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0)) // Option.some(4)
* ```
*
* @see {@link findFirst} — search from the start
* @see {@link findLastIndex} — get the index instead
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option
/**
* Returns the last element matching a predicate, refinement, or mapping
* function, wrapped in `Option`.
*
* - Searches from the end of the array.
* - Returns `Option.none()` if no element matches.
*
* **Example** (Finding the last match)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0)) // Option.some(4)
* ```
*
* @see {@link findFirst} — search from the start
* @see {@link findLastIndex} — get the index instead
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option
} = dual(
2,
(
self: Iterable,
f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option.Option)
): Option.Option => {
const input = fromIterable(self)
for (let i = input.length - 1; i >= 0; i--) {
const a = input[i]
const o = f(a, i)
if (typeof o === "boolean") {
if (o) {
return Option.some(a)
}
} else {
if (Option.isSome(o)) {
return o
}
}
}
return Option.none()
}
)
/**
* Inserts an element at the specified index, returning a new `NonEmptyArray`
* wrapped in an `Option`.
*
* - Valid indices: `0` to `length` (inclusive — inserting at `length` appends).
* - Does not mutate the input.
*
* **Example** (Inserting at an index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.insertAt(["a", "b", "c", "e"], 3, "d")) // Option.some(["a", "b", "c", "d", "e"])
* ```
*
* @see {@link replace} — replace an existing element
* @see {@link modify} — transform an element at an index
*
* @category elements
* @since 2.0.0
*/
export const insertAt: {
/**
* Inserts an element at the specified index, returning a new `NonEmptyArray`
* wrapped in an `Option`.
*
* - Valid indices: `0` to `length` (inclusive — inserting at `length` appends).
* - Does not mutate the input.
*
* **Example** (Inserting at an index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.insertAt(["a", "b", "c", "e"], 3, "d")) // Option.some(["a", "b", "c", "d", "e"])
* ```
*
* @see {@link replace} — replace an existing element
* @see {@link modify} — transform an element at an index
*
* @category elements
* @since 2.0.0
*/
(i: number, b: B): (self: Iterable) => Option.Option>
/**
* Inserts an element at the specified index, returning a new `NonEmptyArray`
* wrapped in an `Option`.
*
* - Valid indices: `0` to `length` (inclusive — inserting at `length` appends).
* - Does not mutate the input.
*
* **Example** (Inserting at an index)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.insertAt(["a", "b", "c", "e"], 3, "d")) // Option.some(["a", "b", "c", "d", "e"])
* ```
*
* @see {@link replace} — replace an existing element
* @see {@link modify} — transform an element at an index
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, i: number, b: B): Option.Option>
} = dual(3, (self: Iterable, i: number, b: B): Option.Option> => {
const out: Array = Array.from(self) // copy because `splice` mutates the array
if (i < 0 || i > out.length) {
return Option.none()
}
out.splice(i, 0, b)
return Option.some(out as any)
})
/**
* Replaces the element at the specified index with a new value, returning a new
* array, wrapped in an `Option`.
*
* - Does not mutate the input.
*
* **Example** (Replacing an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.replace([1, 2, 3], 1, 4)) // Option.some([1, 4, 3])
* ```
*
* @see {@link modify} — transform an element with a function
* @see {@link insertAt} — insert without removing
*
* @category elements
* @since 2.0.0
*/
export const replace: {
/**
* Replaces the element at the specified index with a new value, returning a new
* array, wrapped in an `Option`.
*
* - Does not mutate the input.
*
* **Example** (Replacing an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.replace([1, 2, 3], 1, 4)) // Option.some([1, 4, 3])
* ```
*
* @see {@link modify} — transform an element with a function
* @see {@link insertAt} — insert without removing
*
* @category elements
* @since 2.0.0
*/
(i: number, b: B): = Iterable>(
self: S
) => Option.Option | B>>
/**
* Replaces the element at the specified index with a new value, returning a new
* array, wrapped in an `Option`.
*
* - Does not mutate the input.
*
* **Example** (Replacing an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.replace([1, 2, 3], 1, 4)) // Option.some([1, 4, 3])
* ```
*
* @see {@link modify} — transform an element with a function
* @see {@link insertAt} — insert without removing
*
* @category elements
* @since 2.0.0
*/
= Iterable>(self: S, i: number, b: B): Option.Option | B>>
} = dual(
3,
(self: Iterable, i: number, b: B): Option.Option> => modify(self, i, () => b)
)
/**
* Applies a function to the element at the specified index, returning a new
* array, wrapped in an `Option`.
*
* - Does not mutate the input.
*
* **Example** (Modifying an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.modify([1, 2, 3, 4], 2, (n) => n * 2)) // Option.some([1, 2, 6, 4])
* console.log(Array.modify([1, 2, 3, 4], 5, (n) => n * 2)) // Option.none()
* ```
*
* @see {@link replace} — set a fixed value at an index
* @see {@link modifyHeadNonEmpty} — modify the first element
* @see {@link modifyLastNonEmpty} — modify the last element
*
* @category elements
* @since 2.0.0
*/
export const modify: {
/**
* Applies a function to the element at the specified index, returning a new
* array, wrapped in an `Option`.
*
* - Does not mutate the input.
*
* **Example** (Modifying an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.modify([1, 2, 3, 4], 2, (n) => n * 2)) // Option.some([1, 2, 6, 4])
* console.log(Array.modify([1, 2, 3, 4], 5, (n) => n * 2)) // Option.none()
* ```
*
* @see {@link replace} — set a fixed value at an index
* @see {@link modifyHeadNonEmpty} — modify the first element
* @see {@link modifyLastNonEmpty} — modify the last element
*
* @category elements
* @since 2.0.0
*/
= Iterable>(i: number, f: (a: ReadonlyArray.Infer) => B): (self: S) => Option.Option | B>>
/**
* Applies a function to the element at the specified index, returning a new
* array, wrapped in an `Option`.
*
* - Does not mutate the input.
*
* **Example** (Modifying an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.modify([1, 2, 3, 4], 2, (n) => n * 2)) // Option.some([1, 2, 6, 4])
* console.log(Array.modify([1, 2, 3, 4], 5, (n) => n * 2)) // Option.none()
* ```
*
* @see {@link replace} — set a fixed value at an index
* @see {@link modifyHeadNonEmpty} — modify the first element
* @see {@link modifyLastNonEmpty} — modify the last element
*
* @category elements
* @since 2.0.0
*/
= Iterable>(self: S, i: number, f: (a: ReadonlyArray.Infer) => B): Option.Option | B>>
} = dual(3, (self: Iterable, i: number, f: (a: A) => B): Option.Option> => {
const arr = Array.from(self)
if (isOutOfBounds(i, arr)) {
return Option.none()
}
const out: Array = arr
const b = f(arr[i])
out[i] = b
return Option.some(out)
})
/**
* Removes the element at the specified index, returning a new array. If the
* index is out of bounds, returns a copy of the original.
*
* - Does not mutate the input.
*
* **Example** (Removing an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.remove([1, 2, 3, 4], 2)) // [1, 2, 4]
* console.log(Array.remove([1, 2, 3, 4], 5)) // [1, 2, 3, 4]
* ```
*
* @see {@link insertAt} — insert an element
* @see {@link filter} — remove elements by predicate
*
* @category elements
* @since 2.0.0
*/
export const remove: {
/**
* Removes the element at the specified index, returning a new array. If the
* index is out of bounds, returns a copy of the original.
*
* - Does not mutate the input.
*
* **Example** (Removing an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.remove([1, 2, 3, 4], 2)) // [1, 2, 4]
* console.log(Array.remove([1, 2, 3, 4], 5)) // [1, 2, 3, 4]
* ```
*
* @see {@link insertAt} — insert an element
* @see {@link filter} — remove elements by predicate
*
* @category elements
* @since 2.0.0
*/
(i: number): (self: Iterable) => Array
/**
* Removes the element at the specified index, returning a new array. If the
* index is out of bounds, returns a copy of the original.
*
* - Does not mutate the input.
*
* **Example** (Removing an element)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.remove([1, 2, 3, 4], 2)) // [1, 2, 4]
* console.log(Array.remove([1, 2, 3, 4], 5)) // [1, 2, 3, 4]
* ```
*
* @see {@link insertAt} — insert an element
* @see {@link filter} — remove elements by predicate
*
* @category elements
* @since 2.0.0
*/
(self: Iterable, i: number): Array
} = dual(2, (self: Iterable, i: number): Array => {
const out = Array.from(self)
if (isOutOfBounds(i, out)) {
return out
}
out.splice(i, 1)
return out
})
/**
* Reverses an iterable into a new array.
*
* - Does not mutate the input.
* - Preserves `NonEmptyArray` in the return type.
*
* **Example** (Reversing an array)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.reverse([1, 2, 3, 4])) // [4, 3, 2, 1]
* ```
*
* @category elements
* @since 2.0.0
*/
export const reverse = >(
self: S
): S extends NonEmptyReadonlyArray ? NonEmptyArray : S extends Iterable ? Array : never =>
Array.from(self).reverse() as any
/**
* Sorts an array by the given `Order`, returning a new array.
*
* - Does not mutate the input.
* - Preserves `NonEmptyArray` in the return type.
* - Use {@link sortWith} to sort by a derived key, or {@link sortBy} for
* multi-key sorting.
*
* **Example** (Sorting numbers)
*
* ```ts
* import { Array, Order } from "effect"
*
* console.log(Array.sort([3, 1, 4, 1, 5], Order.Number)) // [1, 1, 3, 4, 5]
* ```
*
* @see {@link sortWith} — sort by a mapping function
* @see {@link sortBy} — sort by multiple orders
*
* @category sorting
* @since 2.0.0
*/
export const sort: {
/**
* Sorts an array by the given `Order`, returning a new array.
*
* - Does not mutate the input.
* - Preserves `NonEmptyArray` in the return type.
* - Use {@link sortWith} to sort by a derived key, or {@link sortBy} for
* multi-key sorting.
*
* **Example** (Sorting numbers)
*
* ```ts
* import { Array, Order } from "effect"
*
* console.log(Array.sort([3, 1, 4, 1, 5], Order.Number)) // [1, 1, 3, 4, 5]
* ```
*
* @see {@link sortWith} — sort by a mapping function
* @see {@link sortBy} — sort by multiple orders
*
* @category sorting
* @since 2.0.0
*/
(O: Order.Order): >(self: S) => ReadonlyArray.With>
/**
* Sorts an array by the given `Order`, returning a new array.
*
* - Does not mutate the input.
* - Preserves `NonEmptyArray` in the return type.
* - Use {@link sortWith} to sort by a derived key, or {@link sortBy} for
* multi-key sorting.
*
* **Example** (Sorting numbers)
*
* ```ts
* import { Array, Order } from "effect"
*
* console.log(Array.sort([3, 1, 4, 1, 5], Order.Number)) // [1, 1, 3, 4, 5]
* ```
*
* @see {@link sortWith} — sort by a mapping function
* @see {@link sortBy} — sort by multiple orders
*
* @category sorting
* @since 2.0.0
*/
(self: NonEmptyReadonlyArray, O: Order.Order): NonEmptyArray
/**
* Sorts an array by the given `Order`, returning a new array.
*
* - Does not mutate the input.
* - Preserves `NonEmptyArray` in the return type.
* - Use {@link sortWith} to sort by a derived key, or {@link sortBy} for
* multi-key sorting.
*
* **Example** (Sorting numbers)
*
* ```ts
* import { Array, Order } from "effect"
*
* console.log(Array.sort([3, 1, 4, 1, 5], Order.Number)) // [1, 1, 3, 4, 5]
* ```
*
* @see {@link sortWith} — sort by a mapping function
* @see {@link sortBy} — sort by multiple orders
*
* @category sorting
* @since 2.0.0
*/
(self: Iterable, O: Order.Order): Array
} = dual(2, (self: Iterable, O: Order.Order): Array => {
const out = Array.from(self)
out.sort(O)
return out
})
/**
* Sorts an array by a derived key using a mapping function and an `Order` for
* that key.
*
* - Equivalent to `sort(Order.mapInput(order, f))` but more convenient.
* - Does not mutate the input.
*
* **Example** (Sorting strings by length)
*
* ```ts
* import { Array, Order } from "effect"
*
* console.log(Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.Number))
* // ["b", "cc", "aaa"]
* ```
*
* @see {@link sort} — sort by a direct `Order`
* @see {@link sortBy} — sort by multiple orders
*
* @since 2.0.0
* @category elements
*/
export const sortWith: {
/**
* Sorts an array by a derived key using a mapping function and an `Order` for
* that key.
*
* - Equivalent to `sort(Order.mapInput(order, f))` but more convenient.
* - Does not mutate the input.
*
* **Example** (Sorting strings by length)
*
* ```ts
* import { Array, Order } from "effect"
*
* console.log(Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.Number))
* // ["b", "cc", "aaa"]
* ```
*
* @see {@link sort} — sort by a direct `Order`
* @see {@link sortBy} — sort by multiple orders
*
* @since 2.0.0
* @category elements
*/
, B>(f: (a: ReadonlyArray.Infer) => B, order: Order.Order): (self: S) => ReadonlyArray.With>
/**
* Sorts an array by a derived key using a mapping function and an `Order` for
* that key.
*
* - Equivalent to `sort(Order.mapInput(order, f))` but more convenient.
* - Does not mutate the input.
*
* **Example** (Sorting strings by length)
*
* ```ts
* import { Array, Order } from "effect"
*
* console.log(Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.Number))
* // ["b", "cc", "aaa"]
* ```
*
* @see {@link sort} — sort by a direct `Order`
* @see {@link sortBy} — sort by multiple orders
*
* @since 2.0.0
* @category elements
*/
(self: NonEmptyReadonlyArray, f: (a: A) => B, O: Order.Order): NonEmptyArray
/**
* Sorts an array by a derived key using a mapping function and an `Order` for
* that key.
*
* - Equivalent to `sort(Order.mapInput(order, f))` but more convenient.
* - Does not mutate the input.
*
* **Example** (Sorting strings by length)
*
* ```ts
* import { Array, Order } from "effect"
*
* console.log(Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.Number))
* // ["b", "cc", "aaa"]
* ```
*
* @see {@link sort} — sort by a direct `Order`
* @see {@link sortBy} — sort by multiple orders
*
* @since 2.0.0
* @category elements
*/
(self: Iterable, f: (a: A) => B, order: Order.Order): Array
} = dual(
3,
(self: Iterable, f: (a: A) => B, order: Order.Order): Array =>
Array.from(self).map((a) => [a, f(a)] as const).sort(([, a], [, b]) => order(a, b)).map(([_]) => _)
)
/**
* Sorts an array by multiple `Order`s applied in sequence: the first order is
* used first; ties are broken by the second order, and so on.
*
* - Data-last only (returns a function).
* - Preserves `NonEmptyArray` in the return type.
*
* **Example** (Multi-key sorting)
*
* ```ts
* import { Array, Order, pipe } from "effect"
*
* const users = [
* { name: "Alice", age: 30 },
* { name: "Bob", age: 25 },
* { name: "Charlie", age: 30 }
* ]
*
* const result = pipe(
* users,
* Array.sortBy(
* Order.mapInput(Order.Number, (user: (typeof users)[number]) => user.age),
* Order.mapInput(Order.String, (user: (typeof users)[number]) => user.name)
* )
* )
* console.log(result)
* // [{ name: "Bob", age: 25 }, { name: "Alice", age: 30 }, { name: "Charlie", age: 30 }]
* ```
*
* @see {@link sort} — sort by a single `Order`
* @see {@link sortWith} — sort by a derived key
*
* @category sorting
* @since 2.0.0
*/
export const sortBy = >(
...orders: ReadonlyArray>>
) => {
const sortByAll = sort(Order.combineAll(orders))
return (
self: S
): S extends NonEmptyReadonlyArray ? NonEmptyArray : S extends Iterable ? Array : never => {
const input = fromIterable(self)
if (isReadonlyArrayNonEmpty(input)) {
return sortByAll(input) as any
}
return [] as any
}
}
/**
* Pairs elements from two iterables by position. If the iterables differ in
* length, the extra elements from the longer one are discarded.
*
* - Returns `NonEmptyArray` when both inputs are non-empty.
*
* **Example** (Zipping two arrays)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zip([1, 2, 3], ["a", "b"])) // [[1, "a"], [2, "b"]]
* ```
*
* @see {@link zipWith} — zip with a combiner function
* @see {@link unzip} — inverse operation
*
* @category zipping
* @since 2.0.0
*/
export const zip: {
/**
* Pairs elements from two iterables by position. If the iterables differ in
* length, the extra elements from the longer one are discarded.
*
* - Returns `NonEmptyArray` when both inputs are non-empty.
*
* **Example** (Zipping two arrays)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zip([1, 2, 3], ["a", "b"])) // [[1, "a"], [2, "b"]]
* ```
*
* @see {@link zipWith} — zip with a combiner function
* @see {@link unzip} — inverse operation
*
* @category zipping
* @since 2.0.0
*/
(that: NonEmptyReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray<[A, B]>
/**
* Pairs elements from two iterables by position. If the iterables differ in
* length, the extra elements from the longer one are discarded.
*
* - Returns `NonEmptyArray` when both inputs are non-empty.
*
* **Example** (Zipping two arrays)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zip([1, 2, 3], ["a", "b"])) // [[1, "a"], [2, "b"]]
* ```
*
* @see {@link zipWith} — zip with a combiner function
* @see {@link unzip} — inverse operation
*
* @category zipping
* @since 2.0.0
*/
(that: Iterable): (self: Iterable) => Array<[A, B]>
/**
* Pairs elements from two iterables by position. If the iterables differ in
* length, the extra elements from the longer one are discarded.
*
* - Returns `NonEmptyArray` when both inputs are non-empty.
*
* **Example** (Zipping two arrays)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zip([1, 2, 3], ["a", "b"])) // [[1, "a"], [2, "b"]]
* ```
*
* @see {@link zipWith} — zip with a combiner function
* @see {@link unzip} — inverse operation
*
* @category zipping
* @since 2.0.0
*/
(self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray<[A, B]>
/**
* Pairs elements from two iterables by position. If the iterables differ in
* length, the extra elements from the longer one are discarded.
*
* - Returns `NonEmptyArray` when both inputs are non-empty.
*
* **Example** (Zipping two arrays)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zip([1, 2, 3], ["a", "b"])) // [[1, "a"], [2, "b"]]
* ```
*
* @see {@link zipWith} — zip with a combiner function
* @see {@link unzip} — inverse operation
*
* @category zipping
* @since 2.0.0
*/
(self: Iterable, that: Iterable): Array<[A, B]>
} = dual(
2,
(self: Iterable, that: Iterable): Array<[A, B]> => zipWith(self, that, Tuple.make)
)
/**
* Combines elements from two iterables pairwise using a function. If the
* iterables differ in length, extra elements are discarded.
*
* **Example** (Zipping with addition)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b)) // [5, 7, 9]
* ```
*
* @see {@link zip} — zip into tuples
*
* @category zipping
* @since 2.0.0
*/
export const zipWith: {
/**
* Combines elements from two iterables pairwise using a function. If the
* iterables differ in length, extra elements are discarded.
*
* **Example** (Zipping with addition)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b)) // [5, 7, 9]
* ```
*
* @see {@link zip} — zip into tuples
*
* @category zipping
* @since 2.0.0
*/
(that: NonEmptyReadonlyArray, f: (a: A, b: B) => C): (self: NonEmptyReadonlyArray) => NonEmptyArray
/**
* Combines elements from two iterables pairwise using a function. If the
* iterables differ in length, extra elements are discarded.
*
* **Example** (Zipping with addition)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b)) // [5, 7, 9]
* ```
*
* @see {@link zip} — zip into tuples
*
* @category zipping
* @since 2.0.0
*/
(that: Iterable, f: (a: A, b: B) => C): (self: Iterable) => Array
/**
* Combines elements from two iterables pairwise using a function. If the
* iterables differ in length, extra elements are discarded.
*
* **Example** (Zipping with addition)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b)) // [5, 7, 9]
* ```
*
* @see {@link zip} — zip into tuples
*
* @category zipping
* @since 2.0.0
*/
(
self: NonEmptyReadonlyArray,
that: NonEmptyReadonlyArray,
f: (a: A, b: B) => C
): NonEmptyArray
/**
* Combines elements from two iterables pairwise using a function. If the
* iterables differ in length, extra elements are discarded.
*
* **Example** (Zipping with addition)
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b)) // [5, 7, 9]
* ```
*
* @see {@link zip} — zip into tuples
*
* @category zipping
* @since 2.0.0
*/
(self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array
} = dual(3, (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array => {
const as = fromIterable(self)
const bs = fromIterable(that)
if (isReadonlyArrayNonEmpty(as) && isReadonlyArrayNonEmpty(bs)) {
const out: NonEmptyArray