effect
Version:
The missing standard library for TypeScript, for writing production-grade software.
1,916 lines • 73.1 kB
JavaScript
/**
* This module provides utility functions for working with arrays in TypeScript.
*
* @since 2.0.0
*/
import * as Either from "./Either.js";
import * as Equal from "./Equal.js";
import * as Equivalence from "./Equivalence.js";
import { dual, identity } from "./Function.js";
import * as internalArray from "./internal/array.js";
import * as internalDoNotation from "./internal/doNotation.js";
import * as moduleIterable from "./Iterable.js";
import * as Option from "./Option.js";
import * as Order from "./Order.js";
import * as Predicate from "./Predicate.js";
import * as Record from "./Record.js";
import * as Tuple from "./Tuple.js";
/**
* Builds a `NonEmptyArray` from an non-empty collection of elements.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.make(1, 2, 3)
* console.log(result) // [1, 2, 3]
* ```
*
* @category constructors
* @since 2.0.0
*/
export const make = (...elements) => elements;
/**
* Creates a new `Array` of the specified length.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.allocate<number>(3)
* console.log(result) // [ <3 empty items> ]
* ```
*
* @category constructors
* @since 2.0.0
*/
export const allocate = n => new Array(n);
/**
* Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`.
*
* **Note**. `n` is normalized to an integer >= 1.
*
* **Example**
*
* ```ts
* import { makeBy } from "effect/Array"
*
* const result = makeBy(5, n => n * 2)
* console.log(result) // [0, 2, 4, 6, 8]
* ```
*
* @category constructors
* @since 2.0.0
*/
export const makeBy = /*#__PURE__*/dual(2, (n, f) => {
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;
});
/**
* Return a `NonEmptyArray` containing a range of integers, including both endpoints.
*
* **Example**
*
* ```ts
* import { range } from "effect/Array"
*
* const result = range(1, 3)
* console.log(result) // [1, 2, 3]
* ```
*
* @category constructors
* @since 2.0.0
*/
export const range = (start, end) => start <= end ? makeBy(end - start + 1, i => start + i) : [start];
/**
* Return a `NonEmptyArray` containing a value repeated the specified number of times.
*
* **Note**. `n` is normalized to an integer >= 1.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.replicate("a", 3)
* console.log(result) // ["a", "a", "a"]
* ```
*
* @category constructors
* @since 2.0.0
*/
export const replicate = /*#__PURE__*/dual(2, (a, n) => makeBy(n, () => a));
/**
* Creates a new `Array` from an iterable collection of values.
* If the input is already an array, it returns the input as-is.
* Otherwise, it converts the iterable collection to an array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.fromIterable(new Set([1, 2, 3]))
* console.log(result) // [1, 2, 3]
* ```
*
* @category constructors
* @since 2.0.0
*/
export const fromIterable = collection => Array.isArray(collection) ? collection : Array.from(collection);
/**
* Creates a new `Array` from a value that might not be an iterable.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.ensure("a")) // ["a"]
* console.log(Array.ensure(["a"])) // ["a"]
* console.log(Array.ensure(["a", "b", "c"])) // ["a", "b", "c"]
* ```
*
* @category constructors
* @since 3.3.0
*/
export const ensure = self => Array.isArray(self) ? self : [self];
/**
* Takes a record and returns an array of tuples containing its keys and values.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.fromRecord({ a: 1, b: 2, c: 3 })
* console.log(result) // [["a", 1], ["b", 2], ["c", 3]]
* ```
*
* @category conversions
* @since 2.0.0
*/
export const fromRecord = Record.toEntries;
/**
* Converts an `Option` to an array.
*
* **Example**
*
* ```ts
* import { Array, Option } from "effect"
*
* console.log(Array.fromOption(Option.some(1))) // [1]
* console.log(Array.fromOption(Option.none())) // []
* ```
*
* @category conversions
* @since 2.0.0
*/
export const fromOption = Option.toArray;
/**
* Matches the elements of an array, applying functions to cases of empty and non-empty arrays.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const match = Array.match({
* onEmpty: () => "empty",
* onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}`
* })
* console.log(match([])) // "empty"
* console.log(match([1, 2, 3])) // "head: 1, tail: 2"
* ```
*
* @category pattern matching
* @since 2.0.0
*/
export const match = /*#__PURE__*/dual(2, (self, {
onEmpty,
onNonEmpty
}) => isNonEmptyReadonlyArray(self) ? onNonEmpty(self) : onEmpty());
/**
* Matches the elements of an array from the left, applying functions to cases of empty and non-empty arrays.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const matchLeft = Array.matchLeft({
* onEmpty: () => "empty",
* onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}`
* })
* console.log(matchLeft([])) // "empty"
* console.log(matchLeft([1, 2, 3])) // "head: 1, tail: 2"
* ```
*
* @category pattern matching
* @since 2.0.0
*/
export const matchLeft = /*#__PURE__*/dual(2, (self, {
onEmpty,
onNonEmpty
}) => isNonEmptyReadonlyArray(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty());
/**
* Matches the elements of an array from the right, applying functions to cases of empty and non-empty arrays.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const matchRight = Array.matchRight({
* onEmpty: () => "empty",
* onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}`
* })
* console.log(matchRight([])) // "empty"
* console.log(matchRight([1, 2, 3])) // "init: 2, last: 3"
* ```
*
* @category pattern matching
* @since 2.0.0
*/
export const matchRight = /*#__PURE__*/dual(2, (self, {
onEmpty,
onNonEmpty
}) => isNonEmptyReadonlyArray(self) ? onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) : onEmpty());
/**
* Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prepend([2, 3, 4], 1)
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @category concatenating
* @since 2.0.0
*/
export const prepend = /*#__PURE__*/dual(2, (self, head) => [head, ...self]);
/**
* Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable).
* If either array is non-empty, the result is also a non-empty array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.prependAll([2, 3], [0, 1])
* console.log(result) // [0, 1, 2, 3]
* ```
*
* @category concatenating
* @since 2.0.0
*/
export const prependAll = /*#__PURE__*/dual(2, (self, that) => fromIterable(that).concat(fromIterable(self)));
/**
* Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.append([1, 2, 3], 4);
* console.log(result) // [1, 2, 3, 4]
* ```
*
* @category concatenating
* @since 2.0.0
*/
export const append = /*#__PURE__*/dual(2, (self, last) => [...self, last]);
/**
* Concatenates two arrays (or iterables), combining their elements.
* If either array is non-empty, the result is also a non-empty array.
*
* @category concatenating
* @since 2.0.0
*/
export const appendAll = /*#__PURE__*/dual(2, (self, that) => fromIterable(self).concat(fromIterable(that)));
/**
* Accumulates values from an `Iterable` starting from the left, storing
* each intermediate result in an array. Useful for tracking the progression of
* a value through a series of transformations.
*
* **Example**
*
* ```ts
* import { Array } from "effect";
*
* const result = Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value)
* console.log(result) // [0, 1, 3, 6, 10]
*
* // Explanation:
* // This function starts with the initial value (0 in this case)
* // and adds each element of the array to this accumulator one by one,
* // keeping track of the cumulative sum after each addition.
* // Each of these sums is captured in the resulting array.
* ```
*
* @category folding
* @since 2.0.0
*/
export const scan = /*#__PURE__*/dual(3, (self, b, f) => {
const out = [b];
let i = 0;
for (const a of self) {
out[i + 1] = f(out[i], a);
i++;
}
return out;
});
/**
* Accumulates values from an `Iterable` starting from the right, storing
* each intermediate result in an array. Useful for tracking the progression of
* a value through a series of transformations.
*
* **Example**
*
* ```ts
* import { Array } from "effect";
*
* const result = Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value)
* console.log(result) // [10, 9, 7, 4, 0]
* ```
*
* @category folding
* @since 2.0.0
*/
export const scanRight = /*#__PURE__*/dual(3, (self, b, f) => {
const input = fromIterable(self);
const out = new Array(input.length + 1);
out[input.length] = b;
for (let i = input.length - 1; i >= 0; i--) {
out[i] = f(out[i + 1], input[i]);
}
return out;
});
/**
* Determine if `unknown` is an Array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isArray(null)) // false
* console.log(Array.isArray([1, 2, 3])) // true
* ```
*
* @category guards
* @since 2.0.0
*/
export const isArray = Array.isArray;
/**
* Determine if an `Array` is empty narrowing down the type to `[]`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isEmptyArray([])) // true
* console.log(Array.isEmptyArray([1, 2, 3])) // false
* ```
*
* @category guards
* @since 2.0.0
*/
export const isEmptyArray = self => self.length === 0;
/**
* Determine if a `ReadonlyArray` is empty narrowing down the type to `readonly []`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isEmptyReadonlyArray([])) // true
* console.log(Array.isEmptyReadonlyArray([1, 2, 3])) // false
* ```
*
* @category guards
* @since 2.0.0
*/
export const isEmptyReadonlyArray = isEmptyArray;
/**
* Determine if an `Array` is non empty narrowing down the type to `NonEmptyArray`.
*
* An `Array` is considered to be a `NonEmptyArray` if it contains at least one element.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isNonEmptyArray([])) // false
* console.log(Array.isNonEmptyArray([1, 2, 3])) // true
* ```
*
* @category guards
* @since 2.0.0
*/
export const isNonEmptyArray = internalArray.isNonEmptyArray;
/**
* Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`.
*
* A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* console.log(Array.isNonEmptyReadonlyArray([])) // false
* console.log(Array.isNonEmptyReadonlyArray([1, 2, 3])) // true
* ```
*
* @category guards
* @since 2.0.0
*/
export const isNonEmptyReadonlyArray = internalArray.isNonEmptyArray;
/**
* Return the number of elements in a `ReadonlyArray`.
*
* @category getters
* @since 2.0.0
*/
export const length = self => self.length;
const isOutOfBounds = (i, as) => i < 0 || i >= as.length;
const clamp = (i, as) => Math.floor(Math.min(Math.max(0, i), as.length));
/**
* This function provides a safe way to read a value at a particular index from a `ReadonlyArray`.
*
* @category getters
* @since 2.0.0
*/
export const get = /*#__PURE__*/dual(2, (self, index) => {
const i = Math.floor(index);
return isOutOfBounds(i, self) ? Option.none() : Option.some(self[i]);
});
/**
* Gets an element unsafely, will throw on out of bounds.
*
* @since 2.0.0
* @category unsafe
*/
export const unsafeGet = /*#__PURE__*/dual(2, (self, index) => {
const i = Math.floor(index);
if (isOutOfBounds(i, self)) {
throw new Error(`Index ${i} out of bounds`);
}
return self[i];
});
/**
* Return a tuple containing the first element, and a new `Array` of the remaining elements, if any.
*
* **Example**
*
* ```ts
* import { Array } from "effect";
*
* const result = Array.unprepend([1, 2, 3, 4])
* console.log(result) // [1, [2, 3, 4]]
* ```
*
* @category splitting
* @since 2.0.0
*/
export const unprepend = self => [headNonEmpty(self), tailNonEmpty(self)];
/**
* Return a tuple containing a copy of the `NonEmptyReadonlyArray` without its last element, and that last element.
*
* **Example**
*
* ```ts
* import { Array } from "effect";
*
* const result = Array.unappend([1, 2, 3, 4])
* console.log(result) // [[1, 2, 3], 4]
* ```
*
* @category splitting
* @since 2.0.0
*/
export const unappend = self => [initNonEmpty(self), lastNonEmpty(self)];
/**
* Get the first element of a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty.
*
* @category getters
* @since 2.0.0
*/
export const head = /*#__PURE__*/get(0);
/**
* Get the first element of a non empty array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.headNonEmpty([1, 2, 3, 4])
* console.log(result) // 1
* ```
*
* @category getters
* @since 2.0.0
*/
export const headNonEmpty = /*#__PURE__*/unsafeGet(0);
/**
* Get the last element in a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty.
*
* @category getters
* @since 2.0.0
*/
export const last = self => isNonEmptyReadonlyArray(self) ? Option.some(lastNonEmpty(self)) : Option.none();
/**
* Get the last element of a non empty array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.lastNonEmpty([1, 2, 3, 4])
* console.log(result) // 4
* ```
*
* @category getters
* @since 2.0.0
*/
export const lastNonEmpty = self => self[self.length - 1];
/**
* Get all but the first element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty.
*
* @category getters
* @since 2.0.0
*/
export const tail = self => {
const input = fromIterable(self);
return isNonEmptyReadonlyArray(input) ? Option.some(tailNonEmpty(input)) : Option.none();
};
/**
* Get all but the first element of a `NonEmptyReadonlyArray`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.tailNonEmpty([1, 2, 3, 4])
* console.log(result) // [2, 3, 4]
* ```
*
* @category getters
* @since 2.0.0
*/
export const tailNonEmpty = self => self.slice(1);
/**
* Get all but the last element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty.
*
* @category getters
* @since 2.0.0
*/
export const init = self => {
const input = fromIterable(self);
return isNonEmptyReadonlyArray(input) ? Option.some(initNonEmpty(input)) : Option.none();
};
/**
* Get all but the last element of a non empty array, creating a new array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.initNonEmpty([1, 2, 3, 4])
* console.log(result) // [1, 2, 3]
* ```
*
* @category getters
* @since 2.0.0
*/
export const initNonEmpty = self => self.slice(0, -1);
/**
* Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`.
*
* **Note**. `n` is normalized to a non negative integer.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.take([1, 2, 3, 4, 5], 3)
* console.log(result) // [1, 2, 3]
* ```
*
* @category getters
* @since 2.0.0
*/
export const take = /*#__PURE__*/dual(2, (self, n) => {
const input = fromIterable(self);
return input.slice(0, clamp(n, input));
});
/**
* Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`.
*
* **Note**. `n` is normalized to a non negative integer.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.takeRight([1, 2, 3, 4, 5], 3)
* console.log(result) // [3, 4, 5]
* ```
*
* @category getters
* @since 2.0.0
*/
export const takeRight = /*#__PURE__*/dual(2, (self, n) => {
const input = fromIterable(self);
const i = clamp(n, input);
return i === 0 ? [] : input.slice(-i);
});
/**
* Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4)
* console.log(result) // [1, 3, 2]
*
* // Explanation:
* // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result.
* // - The next element (`3`) is also less than `4`, so it adds `3`.
* // - The next element (`2`) is again less than `4`, so it adds `2`.
* // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result.
* ```
*
* @category getters
* @since 2.0.0
*/
export const takeWhile = /*#__PURE__*/dual(2, (self, predicate) => {
let i = 0;
const out = [];
for (const a of self) {
if (!predicate(a, i)) {
break;
}
out.push(a);
i++;
}
return out;
});
const spanIndex = (self, predicate) => {
let i = 0;
for (const a of self) {
if (!predicate(a, i)) {
break;
}
i++;
}
return i;
};
/**
* Split an `Iterable` into two parts:
*
* 1. the longest initial subarray for which all elements satisfy the specified predicate
* 2. the remaining elements
*
* @category splitting
* @since 2.0.0
*/
export const span = /*#__PURE__*/dual(2, (self, predicate) => splitAt(self, spanIndex(self, predicate)));
/**
* Drop a max number of elements from the start of an `Iterable`, creating a new `Array`.
*
* **Note**. `n` is normalized to a non negative integer.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.drop([1, 2, 3, 4, 5], 2)
* console.log(result) // [3, 4, 5]
* ```
*
* @category getters
* @since 2.0.0
*/
export const drop = /*#__PURE__*/dual(2, (self, n) => {
const input = fromIterable(self);
return input.slice(clamp(n, input), input.length);
});
/**
* Drop a max number of elements from the end of an `Iterable`, creating a new `Array`.
*
* **Note**. `n` is normalized to a non negative integer.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.dropRight([1, 2, 3, 4, 5], 2)
* console.log(result) // [1, 2, 3]
* ```
*
* @category getters
* @since 2.0.0
*/
export const dropRight = /*#__PURE__*/dual(2, (self, n) => {
const input = fromIterable(self);
return input.slice(0, input.length - clamp(n, input));
});
/**
* Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.dropWhile([1, 2, 3, 4, 5], x => x < 4)
* console.log(result) // [4, 5]
* ```
*
* @category getters
* @since 2.0.0
*/
export const dropWhile = /*#__PURE__*/dual(2, (self, predicate) => fromIterable(self).slice(spanIndex(self, predicate)));
/**
* Return the first index for which a predicate holds.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.findFirstIndex([5, 3, 8, 9], x => x > 5)
* console.log(result) // Option.some(2)
* ```
*
* @category elements
* @since 2.0.0
*/
export const findFirstIndex = /*#__PURE__*/dual(2, (self, predicate) => {
let i = 0;
for (const a of self) {
if (predicate(a, i)) {
return Option.some(i);
}
i++;
}
return Option.none();
});
/**
* Return the last index for which a predicate holds.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.findLastIndex([1, 3, 8, 9], x => x < 5)
* console.log(result) // Option.some(1)
* ```
*
* @category elements
* @since 2.0.0
*/
export const findLastIndex = /*#__PURE__*/dual(2, (self, predicate) => {
const input = fromIterable(self);
for (let i = input.length - 1; i >= 0; i--) {
if (predicate(input[i], i)) {
return Option.some(i);
}
}
return Option.none();
});
/**
* Returns the first element that satisfies the specified
* predicate, or `None` if no such element exists.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3)
* console.log(result) // Option.some(4)
* ```
*
* @category elements
* @since 2.0.0
*/
export const findFirst = moduleIterable.findFirst;
/**
* Finds the last element in an iterable collection that satisfies the given predicate or refinement.
* Returns an `Option` containing the found element, or `Option.none` if no element matches.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.findLast([1, 2, 3, 4, 5], n => n % 2 === 0)
* console.log(result) // Option.some(4)
* ```
*
* @category elements
* @since 2.0.0
*/
export const findLast = /*#__PURE__*/dual(2, (self, f) => {
const input = fromIterable(self);
for (let i = input.length - 1; i >= 0; i--) {
const a = input[i];
const o = f(a, i);
if (Predicate.isBoolean(o)) {
if (o) {
return Option.some(a);
}
} else {
if (Option.isSome(o)) {
return o;
}
}
}
return Option.none();
});
/**
* Returns a tuple of the first element that satisfies the specified
* predicate and its index, or `None` if no such element exists.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.findFirstWithIndex([1, 2, 3, 4, 5], x => x > 3)
* console.log(result) // Option.some([4, 3])
* ```
*
* @category elements
* @since 3.17.0
*/
export const findFirstWithIndex = /*#__PURE__*/dual(2, (self, f) => {
let i = 0;
for (const a of self) {
const o = f(a, i);
if (Predicate.isBoolean(o)) {
if (o) {
return Option.some([a, i]);
}
} else {
if (Option.isSome(o)) {
return Option.some([o.value, i]);
}
}
i++;
}
return Option.none();
});
/**
* Counts all the element of the given array that pass the given predicate
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.countBy([1, 2, 3, 4, 5], n => n % 2 === 0)
* console.log(result) // 2
* ```
*
* @category folding
* @since 3.16.0
*/
export const countBy = /*#__PURE__*/dual(2, (self, f) => {
let count = 0;
const as = fromIterable(self);
for (let i = 0; i < as.length; i++) {
const a = as[i];
if (f(a, i)) {
count++;
}
}
return count;
});
/**
* Insert an element at the specified index, creating a new `NonEmptyArray`,
* or return `None` if the index is out of bounds.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.insertAt(['a', 'b', 'c', 'e'], 3, 'd')
* console.log(result) // Option.some(['a', 'b', 'c', 'd', 'e'])
* ```
*
* @since 2.0.0
*/
export const insertAt = /*#__PURE__*/dual(3, (self, i, b) => {
const out = Array.from(self);
// v--- `= self.length` is ok, it means inserting in last position
if (i < 0 || i > out.length) {
return Option.none();
}
out.splice(i, 0, b);
return Option.some(out);
});
/**
* Change the element at the specified index, creating a new `Array`,
* or return a copy of the input if the index is out of bounds.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.replace(['a', 'b', 'c', 'd'], 1, 'z')
* console.log(result) // ['a', 'z', 'c', 'd']
* ```
*
* @since 2.0.0
*/
export const replace = /*#__PURE__*/dual(3, (self, i, b) => modify(self, i, () => b));
/**
* Replaces an element in an array with the given value, returning an option of the updated array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.replaceOption([1, 2, 3], 1, 4)
* console.log(result) // Option.some([1, 4, 3])
* ```
*
* @since 2.0.0
*/
export const replaceOption = /*#__PURE__*/dual(3, (self, i, b) => modifyOption(self, i, () => b));
/**
* Apply a function to the element at the specified index, creating a new `Array`,
* or return a copy of the input if the index is out of bounds.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.modify([1, 2, 3, 4], 2, (n) => n * 2)
* console.log(result) // [1, 2, 6, 4]
* ```
*
* @since 2.0.0
*/
export const modify = /*#__PURE__*/dual(3, (self, i, f) => {
const out = Array.from(self);
if (isOutOfBounds(i, out)) {
return out;
}
const b = f(out[i]);
out[i] = b;
return out;
});
/**
* Apply a function to the element at the specified index, creating a new `Array`,
* or return `None` if the index is out of bounds.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const input = [1, 2, 3, 4]
* const result = Array.modifyOption(input, 2, (n) => n * 2)
* console.log(result) // Option.some([1, 2, 6, 4])
*
* const outOfBoundsResult = Array.modifyOption(input, 5, (n) => n * 2)
* console.log(outOfBoundsResult) // Option.none()
* ```
*
* @since 2.0.0
*/
export const modifyOption = /*#__PURE__*/dual(3, (self, i, f) => {
const arr = fromIterable(self);
if (isOutOfBounds(i, arr)) {
return Option.none();
}
const out = Array.isArray(self) ? self.slice() : arr;
const b = f(arr[i]);
out[i] = b;
return Option.some(out);
});
/**
* Delete the element at the specified index, creating a new `Array`,
* or return a copy of the input if the index is out of bounds.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const input = [1, 2, 3, 4]
* const result = Array.remove(input, 2)
* console.log(result) // [1, 2, 4]
*
* const outOfBoundsResult = Array.remove(input, 5)
* console.log(outOfBoundsResult) // [1, 2, 3, 4]
* ```
*
* @since 2.0.0
*/
export const remove = /*#__PURE__*/dual(2, (self, i) => {
const out = Array.from(self);
if (isOutOfBounds(i, out)) {
return out;
}
out.splice(i, 1);
return out;
});
/**
* Delete the element at the specified index, creating a new `Array`,
* or return `None` if the index is out of bounds.
*
* @example
* ```ts
* import * as assert from "node:assert"
* import { Array, Option } from "effect"
*
* const numbers = [1, 2, 3, 4]
* const result = Array.removeOption(numbers, 2)
* assert.deepStrictEqual(result, Option.some([1, 2, 4]))
*
* const outOfBoundsResult = Array.removeOption(numbers, 5)
* assert.deepStrictEqual(outOfBoundsResult, Option.none())
* ```
*
* @since 3.16.0
*/
export const removeOption = /*#__PURE__*/dual(2, (self, i) => {
const arr = fromIterable(self);
if (isOutOfBounds(i, arr)) {
return Option.none();
}
const out = Array.isArray(self) ? self.slice() : arr;
out.splice(i, 1);
return Option.some(out);
});
/**
* Reverse an `Iterable`, creating a new `Array`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.reverse([1, 2, 3, 4])
* console.log(result) // [4, 3, 2, 1]
* ```
*
* @category elements
* @since 2.0.0
*/
export const reverse = self => Array.from(self).reverse();
/**
* Create a new array with elements sorted in increasing order based on the specified comparator.
* If the input is a `NonEmptyReadonlyArray`, the output will also be a `NonEmptyReadonlyArray`.
*
* @category sorting
* @since 2.0.0
*/
export const sort = /*#__PURE__*/dual(2, (self, O) => {
const out = Array.from(self);
out.sort(O);
return out;
});
/**
* Sorts an array based on a provided mapping function and order. The mapping
* function transforms the elements into a value that can be compared, and the
* order defines how those values should be sorted.
*
* **Example**
*
* ```ts
* import { Array, Order } from "effect"
*
* const result = Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.number)
* console.log(result) // ["b", "cc", "aaa"]
*
* // Explanation:
* // The array of strings is sorted based on their lengths. The mapping function `(s) => s.length`
* // converts each string into its length, and the `Order.number` specifies that the lengths should
* // be sorted in ascending order.
* ```
*
* @since 2.0.0
* @category elements
*/
export const sortWith = /*#__PURE__*/dual(3, (self, f, order) => Array.from(self).map(a => [a, f(a)]).sort(([, a], [, b]) => order(a, b)).map(([_]) => _));
/**
* Sorts the elements of an `Iterable` in increasing order based on the provided
* orders. The elements are compared using the first order in `orders`, then the
* second order if the first comparison is equal, and so on.
*
* **Example**
*
* ```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 }
* // ]
*
* // Explanation:
* // The array of users is sorted first by age in ascending order. When ages are equal,
* // the users are further sorted by name in ascending order.
* ```
*
* @category sorting
* @since 2.0.0
*/
export const sortBy = (...orders) => {
const sortByAll = sort(Order.combineAll(orders));
return self => {
const input = fromIterable(self);
if (isNonEmptyReadonlyArray(input)) {
return sortByAll(input);
}
return [];
};
};
/**
* Takes two `Iterable`s and returns an `Array` of corresponding pairs.
* If one input `Iterable` is short, excess elements of the
* longer `Iterable` are discarded.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.zip([1, 2, 3], ['a', 'b'])
* console.log(result) // [[1, 'a'], [2, 'b']]
* ```
*
* @category zipping
* @since 2.0.0
*/
export const zip = /*#__PURE__*/dual(2, (self, that) => zipWith(self, that, Tuple.make));
/**
* Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one
* input `Iterable` is short, excess elements of the longer `Iterable` are discarded.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b)
* console.log(result) // [5, 7, 9]
* ```
*
* @category zipping
* @since 2.0.0
*/
export const zipWith = /*#__PURE__*/dual(3, (self, that, f) => {
const as = fromIterable(self);
const bs = fromIterable(that);
if (isNonEmptyReadonlyArray(as) && isNonEmptyReadonlyArray(bs)) {
const out = [f(headNonEmpty(as), headNonEmpty(bs))];
const len = Math.min(as.length, bs.length);
for (let i = 1; i < len; i++) {
out[i] = f(as[i], bs[i]);
}
return out;
}
return [];
});
/**
* This function is the inverse of `zip`. Takes an `Iterable` of pairs and return two corresponding `Array`s.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.unzip([[1, "a"], [2, "b"], [3, "c"]])
* console.log(result) // [[1, 2, 3], ['a', 'b', 'c']]
* ```
*
* @since 2.0.0
*/
export const unzip = self => {
const input = fromIterable(self);
if (isNonEmptyReadonlyArray(input)) {
const fa = [input[0][0]];
const fb = [input[0][1]];
for (let i = 1; i < input.length; i++) {
fa[i] = input[i][0];
fb[i] = input[i][1];
}
return [fa, fb];
}
return [[], []];
};
/**
* Places an element in between members of an `Iterable`.
* If the input is a non-empty array, the result is also a non-empty array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.intersperse([1, 2, 3], 0)
* console.log(result) // [1, 0, 2, 0, 3]
* ```
*
* @since 2.0.0
*/
export const intersperse = /*#__PURE__*/dual(2, (self, middle) => {
const input = fromIterable(self);
if (isNonEmptyReadonlyArray(input)) {
const out = [headNonEmpty(input)];
const tail = tailNonEmpty(input);
for (let i = 0; i < tail.length; i++) {
if (i < tail.length) {
out.push(middle);
}
out.push(tail[i]);
}
return out;
}
return [];
});
/**
* Apply a function to the head, creating a new `NonEmptyReadonlyArray`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.modifyNonEmptyHead([1, 2, 3], n => n * 10)
* console.log(result) // [10, 2, 3]
* ```
*
* @since 2.0.0
*/
export const modifyNonEmptyHead = /*#__PURE__*/dual(2, (self, f) => [f(headNonEmpty(self)), ...tailNonEmpty(self)]);
/**
* Change the head, creating a new `NonEmptyReadonlyArray`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.setNonEmptyHead([1, 2, 3], 10)
* console.log(result) // [10, 2, 3]
* ```
*
* @since 2.0.0
*/
export const setNonEmptyHead = /*#__PURE__*/dual(2, (self, b) => modifyNonEmptyHead(self, () => b));
/**
* Apply a function to the last element, creating a new `NonEmptyReadonlyArray`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.modifyNonEmptyLast([1, 2, 3], n => n * 2)
* console.log(result) // [1, 2, 6]
* ```
*
* @since 2.0.0
*/
export const modifyNonEmptyLast = /*#__PURE__*/dual(2, (self, f) => append(initNonEmpty(self), f(lastNonEmpty(self))));
/**
* Change the last element, creating a new `NonEmptyReadonlyArray`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.setNonEmptyLast([1, 2, 3], 4)
* console.log(result) // [1, 2, 4]
* ```
*
* @since 2.0.0
*/
export const setNonEmptyLast = /*#__PURE__*/dual(2, (self, b) => modifyNonEmptyLast(self, () => b));
/**
* Rotate an `Iterable` by `n` steps.
* If the input is a non-empty array, the result is also a non-empty array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.rotate(['a', 'b', 'c', 'd', 'e'], 2)
* console.log(result) // [ 'd', 'e', 'a', 'b', 'c' ]
* ```
*
* @since 2.0.0
*/
export const rotate = /*#__PURE__*/dual(2, (self, n) => {
const input = fromIterable(self);
if (isNonEmptyReadonlyArray(input)) {
const len = input.length;
const m = Math.round(n) % len;
if (isOutOfBounds(Math.abs(m), input) || m === 0) {
return copy(input);
}
if (m < 0) {
const [f, s] = splitNonEmptyAt(input, -m);
return appendAll(s, f);
} else {
return rotate(self, m - len);
}
}
return [];
});
/**
* Returns a function that checks if a `ReadonlyArray` contains a given value using a provided `isEquivalent` function.
*
* **Example**
*
* ```ts
* import { Array, pipe } from "effect"
*
* const isEquivalent = (a: number, b: number) => a === b
* const containsNumber = Array.containsWith(isEquivalent)
* const result = pipe([1, 2, 3, 4], containsNumber(3))
* console.log(result) // true
* ```
*
* @category elements
* @since 2.0.0
*/
export const containsWith = isEquivalent => dual(2, (self, a) => {
for (const i of self) {
if (isEquivalent(a, i)) {
return true;
}
}
return false;
});
const _equivalence = /*#__PURE__*/Equal.equivalence();
/**
* Returns a function that checks if a `ReadonlyArray` contains a given value using the default `Equivalence`.
*
* **Example**
*
* ```ts
* import { Array, pipe } from "effect"
*
* const result = pipe(['a', 'b', 'c', 'd'], Array.contains('c'))
* console.log(result) // true
* ```
*
* @category elements
* @since 2.0.0
*/
export const contains = /*#__PURE__*/containsWith(_equivalence);
/**
* A useful recursion pattern for processing an `Iterable` to produce a new `Array`, often used for "chopping" up the input
* `Iterable`. Typically chop is called with some function that will consume an initial prefix of the `Iterable` and produce a
* value and the rest of the `Array`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.chop([1, 2, 3, 4, 5], (as): [number, Array<number>] => [as[0] * 2, as.slice(1)])
* console.log(result) // [2, 4, 6, 8, 10]
*
* // Explanation:
* // The `chopFunction` takes the first element of the array, doubles it, and then returns it along with the rest of the array.
* // The `chop` function applies this `chopFunction` recursively to the input array `[1, 2, 3, 4, 5]`,
* // resulting in a new array `[2, 4, 6, 8, 10]`.
* ```
*
* @since 2.0.0
*/
export const chop = /*#__PURE__*/dual(2, (self, f) => {
const input = fromIterable(self);
if (isNonEmptyReadonlyArray(input)) {
const [b, rest] = f(input);
const out = [b];
let next = rest;
while (internalArray.isNonEmptyArray(next)) {
const [b, rest] = f(next);
out.push(b);
next = rest;
}
return out;
}
return [];
});
/**
* Splits an `Iterable` into two segments, with the first segment containing a maximum of `n` elements.
* The value of `n` can be `0`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.splitAt([1, 2, 3, 4, 5], 3)
* console.log(result) // [[1, 2, 3], [4, 5]]
* ```
*
* @category splitting
* @since 2.0.0
*/
export const splitAt = /*#__PURE__*/dual(2, (self, n) => {
const input = Array.from(self);
const _n = Math.floor(n);
if (isNonEmptyReadonlyArray(input)) {
if (_n >= 1) {
return splitNonEmptyAt(input, _n);
}
return [[], input];
}
return [input, []];
});
/**
* Splits a `NonEmptyReadonlyArray` into two segments, with the first segment containing a maximum of `n` elements.
* The value of `n` must be `>= 1`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.splitNonEmptyAt(["a", "b", "c", "d", "e"], 3)
* console.log(result) // [["a", "b", "c"], ["d", "e"]]
* ```
*
* @category splitting
* @since 2.0.0
*/
export const splitNonEmptyAt = /*#__PURE__*/dual(2, (self, n) => {
const _n = Math.max(1, Math.floor(n));
return _n >= self.length ? [copy(self), []] : [prepend(self.slice(1, _n), headNonEmpty(self)), self.slice(_n)];
});
/**
* Splits this iterable into `n` equally sized arrays.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.split([1, 2, 3, 4, 5, 6, 7, 8], 3)
* console.log(result) // [[1, 2, 3], [4, 5, 6], [7, 8]]
* ```
*
* @since 2.0.0
* @category splitting
*/
export const split = /*#__PURE__*/dual(2, (self, n) => {
const input = fromIterable(self);
return chunksOf(input, Math.ceil(input.length / Math.floor(n)));
});
/**
* Splits this iterable on the first element that matches this predicate.
* Returns a tuple containing two arrays: the first one is before the match, and the second one is from the match onward.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.splitWhere([1, 2, 3, 4, 5], n => n > 3)
* console.log(result) // [[1, 2, 3], [4, 5]]
* ```
*
* @category splitting
* @since 2.0.0
*/
export const splitWhere = /*#__PURE__*/dual(2, (self, predicate) => span(self, (a, i) => !predicate(a, i)));
/**
* Copies an array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.copy([1, 2, 3])
* console.log(result) // [1, 2, 3]
* ```
*
* @since 2.0.0
*/
export const copy = self => self.slice();
/**
* Pads an array.
* Returns a new array of length `n` with the elements of `array` followed by `fill` elements if `array` is shorter than `n`.
* If `array` is longer than `n`, the returned array will be a slice of `array` containing the `n` first elements of `array`.
* If `n` is less than or equal to 0, the returned array will be an empty array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.pad([1, 2, 3], 6, 0)
* console.log(result) // [1, 2, 3, 0, 0, 0]
* ```
*
* @since 3.8.4
*/
export const pad = /*#__PURE__*/dual(3, (self, n, fill) => {
if (self.length >= n) {
return take(self, n);
}
return appendAll(self, makeBy(n - self.length, () => fill));
});
/**
* Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of
* the `Iterable`. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive
* definition of `chunksOf`; it satisfies the property that
*
* ```ts skip-type-checking
* chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys)))
* ```
*
* whenever `n` evenly divides the length of `self`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.chunksOf([1, 2, 3, 4, 5], 2)
* console.log(result) // [[1, 2], [3, 4], [5]]
*
* // Explanation:
* // The `chunksOf` function takes an array of numbers `[1, 2, 3, 4, 5]` and a number `2`.
* // It splits the array into chunks of length 2. Since the array length is not evenly divisible by 2,
* // the last chunk contains the remaining elements.
* // The result is `[[1, 2], [3, 4], [5]]`.
* ```
*
* @category splitting
* @since 2.0.0
*/
export const chunksOf = /*#__PURE__*/dual(2, (self, n) => {
const input = fromIterable(self);
if (isNonEmptyReadonlyArray(input)) {
return chop(input, splitNonEmptyAt(n));
}
return [];
});
/**
* Creates sliding windows of size `n` from an `Iterable`.
* If the number of elements is less than `n` or if `n` is not greater than zero,
* an empty array is returned.
*
* @example
* ```ts
* import * as assert from "node:assert"
* import { Array } from "effect"
*
* const numbers = [1, 2, 3, 4, 5]
* assert.deepStrictEqual(Array.window(numbers, 3), [[1, 2, 3], [2, 3, 4], [3, 4, 5]])
* assert.deepStrictEqual(Array.window(numbers, 6), [])
* ```
*
* @category splitting
* @since 3.13.2
*/
export const window = /*#__PURE__*/dual(2, (self, n) => {
const input = fromIterable(self);
if (n > 0 && isNonEmptyReadonlyArray(input)) {
return Array.from({
length: input.length - (n - 1)
}, (_, index) => input.slice(index, index + n));
}
return [];
});
/**
* Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s using the provided `isEquivalent` function.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.groupWith(["a", "a", "b", "b", "b", "c", "a"], (x, y) => x === y)
* console.log(result) // [["a", "a"], ["b", "b", "b"], ["c"], ["a"]]
* ```
*
* @category grouping
* @since 2.0.0
*/
export const groupWith = /*#__PURE__*/dual(2, (self, isEquivalent) => chop(self, as => {
const h = headNonEmpty(as);
const out = [h];
let i = 1;
for (; i < as.length; i++) {
const a = as[i];
if (isEquivalent(a, h)) {
out.push(a);
} else {
break;
}
}
return [out, as.slice(i)];
}));
/**
* Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.group([1, 1, 2, 2, 2, 3, 1])
* console.log(result) // [[1, 1], [2, 2, 2], [3], [1]]
* ```
*
* @category grouping
* @since 2.0.0
*/
export const group = /*#__PURE__*/groupWith(/*#__PURE__*/Equal.equivalence());
/**
* Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning
* function on each element, and grouping the results according to values returned
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const people = [
* { name: "Alice", group: "A" },
* { name: "Bob", group: "B" },
* { name: "Charlie", group: "A" }
* ]
*
* const result = Array.groupBy(people, person => person.group)
* console.log(result)
* // {
* // A: [{ name: "Alice", group: "A" }, { name: "Charlie", group: "A" }],
* // B: [{ name: "Bob", group: "B" }]
* // }
* ```
*
* @category grouping
* @since 2.0.0
*/
export const groupBy = /*#__PURE__*/dual(2, (self, f) => {
const out = {};
for (const a of self) {
const k = f(a);
if (Object.prototype.hasOwnProperty.call(out, k)) {
out[k].push(a);
} else {
out[k] = [a];
}
}
return out;
});
/**
* Calculates the union of two arrays using the provided equivalence relation.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const union = Array.unionWith([1, 2], [2, 3], (a, b) => a === b)
* console.log(union) // [1, 2, 3]
* ```
*
* @since 2.0.0
*/
export const unionWith = /*#__PURE__*/dual(3, (self, that, isEquivalent) => {
const a = fromIterable(self);
const b = fromIterable(that);
if (isNonEmptyReadonlyArray(a)) {
if (isNonEmptyReadonlyArray(b)) {
const dedupe = dedupeWith(isEquivalent);
return dedupe(appendAll(a, b));
}
return a;
}
return b;
});
/**
* Creates a union of two arrays, removing duplicates.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.union([1, 2], [2, 3])
* console.log(result) // [1, 2, 3]
* ```
*
* @since 2.0.0
*/
export const union = /*#__PURE__*/dual(2, (self, that) => unionWith(self, that, _equivalence));
/**
* Creates an `Array` of unique values that are included in all given `Iterable`s using the provided `isEquivalent` function.
* The order and references of result values are determined by the first `Iterable`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const array1 = [{ id: 1 }, { id: 2 }, { id: 3 }]
* const array2 = [{ id: 3 }, { id: 4 }, { id: 1 }]
* const isEquivalent = (a: { id: number }, b: { id: number }) => a.id === b.id
* const result = Array.intersectionWith(isEquivalent)(array2)(array1)
* console.log(result) // [{ id: 1 }, { id: 3 }]
* ```
*
* @since 2.0.0
*/
export const intersectionWith = isEquivalent => {
const has = containsWith(isEquivalent);
return dual(2, (self, that) => {
const bs = fromIterable(that);
return fromIterable(self).filter(a => has(bs, a));
});
};
/**
* Creates an `Array` of unique values that are included in all given `Iterable`s.
* The order and references of result values are determined by the first `Iterable`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.intersection([1, 2, 3], [3, 4, 1])
* console.log(result) // [1, 3]
* ```
*
* @since 2.0.0
*/
export const intersection = /*#__PURE__*/intersectionWith(_equivalence);
/**
* Creates a `Array` of values not included in the other given `Iterable` using the provided `isEquivalent` function.
* The order and references of result values are determined by the first `Iterable`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const array1 = [1, 2, 3]
* const array2 = [2, 3, 4]
* const difference = Array.differenceWith<number>((a, b) => a === b)(array1, array2)
* console.log(difference) // [1]
* ```
*
* @since 2.0.0
*/
export const differenceWith = isEquivalent => {
const has = containsWith(isEquivalent);
return dual(2, (self, that) => {
const bs = fromIterable(that);
return fromIterable(self).filter(a => !has(bs, a));
});
};
/**
* Creates a `Array` of values not included in the other given `Iterable`.
* The order and references of result values are determined by the first `Iterable`.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const difference = Array.difference([1, 2, 3], [2, 3, 4])
* console.log(difference) // [1]
* ```
*
* @since 2.0.0
*/
export const difference = /*#__PURE__*/differenceWith(_equivalence);
/**
* @category constructors
* @since 2.0.0
*/
export const empty = () => [];
/**
* Constructs a new `NonEmptyArray<A>` from the specified value.
*
* @category constructors
* @since 2.0.0
*/
export const of = a => [a];
/**
* @category mapping
* @since 2.0.0
*/
export const map = /*#__PURE__*/dual(2, (self, f) => self.map(f));
/**
* Applies a function to each element in an array and returns a new array containing the concatenated mapped elements.
*
* @category sequencing
* @since 2.0.0
*/
export const flatMap = /*#__PURE__*/dual(2, (self, f) => {
if (isEmptyReadonlyArray(self)) {
return [];
}
const out = [];
for (let i = 0; i < self.length; i++) {
const inner = f(self[i], i);
for (let j = 0; j < inner.length; j++) {
out.push(inner[j]);
}
}
return out;
});
/**
* Combines multiple arrays into a single array by concatenating all elements
* from each nested array. This function ensures that the structure of nested
* arrays is collapsed into a single, flat array.
*
* **Example**
*
* ```ts
* import { Array } from "effect"
*
* const result = Array.flatten([[1, 2], [], [3, 4], [], [5, 6]])
* console.log(result) // [1, 2, 3, 4, 5, 6]
* ```
*
* @category sequencing
* @since 2.0.0
*/
export const flatten = /*#__PURE__*/flatMap(identity);
/**
* Applies a function to each element of the `Iterable` and filters based on the result, keeping the transformed values where the function returns `Some`.
* This method combines filtering and mapping functionalities, allowing transformations and filtering of elements based on a single function pass.
*
* **Example**
*
* ```ts
* import { Array, Option } from "effect"
*
* const evenSquares = (x: number) => x % 2 === 0 ? Option.some(x * x) : Option.none()
*
* const result = Array.filterMap([1, 2, 3, 4, 5], evenSquares);
* console.log(result) // [4, 16]
* ```
*
* @category filtering
* @since 2.0.0
*/
export const filterMap = /*#__PURE__*/dual(2, (self, f) => {