1/**
2 * Works with JavaScript arrays, readonly arrays, and non-empty arrays.
3 *
4 * The helpers cover common collection work such as creating arrays, reading
5 * elements, transforming values, sorting, grouping, splitting, combining, and
6 * reducing many values to one result. Helpers that change contents return new
7 * arrays and preserve non-empty array types when the result is guaranteed to
8 * contain values.
9 *
10 * @since 2.0.0
11 */
12import * as Equal from "./Equal.ts"
13import * as Equivalence from "./Equivalence.ts"
14import type { LazyArg } from "./Function.ts"
15import { dual, identity } from "./Function.ts"
16import * as Hash from "./Hash.ts"
17import type { TypeLambda } from "./HKT.ts"
18import * as internalArray from "./internal/array.ts"
19import * as Count from "./internal/count.ts"
20import * as internalDoNotation from "./internal/doNotation.ts"
21import * as InternalRecord from "./internal/record.ts"
22import * as moduleIterable from "./Iterable.ts"
23import * as Option from "./Option.ts"
24import * as Order from "./Order.ts"
25import type * as Predicate from "./Predicate.ts"
26import * as Record from "./Record.ts"
27import * as Reducer from "./Reducer.ts"
28import * as Result from "./Result.ts"
29import * as Tuple from "./Tuple.ts"
30import type { NoInfer, TupleOf } from "./Types.ts"
31
32/**
33 * Exposes the global array constructor.
34 *
35 * **When to use**
36 *
37 * Use to access native JavaScript array constructor methods such as `isArray`
38 * or `from` from the Effect module namespace.
39 *
40 * **Example** (Accessing the Array constructor)
41 *
42 * ```ts import.meta.vitest
43 * import { Array } from "effect"
44 *
45 * Array.Array === globalThis.Array // => true
46 * ```
47 *
48 * @category constructors
49 * @since 4.0.0
50 */
51export const Array = globalThis.Array
52
53/**
54 * Type lambda for `ReadonlyArray`, used for higher-kinded type operations.
55 *
56 * @category utility types
57 * @since 2.0.0
58 */
59export interface ReadonlyArrayTypeLambda extends TypeLambda {
60 readonly type: ReadonlyArray<this["Target"]>
61}
62
63/**
64 * A readonly array guaranteed to have at least one element.
65 *
66 * **When to use**
67 *
68 * Use when non-emptiness must be tracked at the type level while preventing mutation.
69 * Many Array module functions accept or return this type.
70 *
71 * **Example** (Typing a non-empty array)
72 *
73 * ```ts import.meta.vitest
74 * import type { Array } from "effect"
75 *
76 * const nonEmpty: Array.NonEmptyReadonlyArray<number> = [1, 2, 3]
77 * const head: number = nonEmpty[0] // guaranteed to exist
78 *
79 * head // => 1
80 * ```
81 *
82 * @see {@link NonEmptyArray} — mutable counterpart
83 * @see {@link isReadonlyArrayNonEmpty} — narrow a `ReadonlyArray` to this type
84 *
85 * @category models
86 * @since 2.0.0
87 */
88export type NonEmptyReadonlyArray<A> = readonly [A, ...Array<A>]
89
90/**
91 * A mutable array guaranteed to have at least one element.
92 *
93 * **When to use**
94 *
95 * Use when mutation is acceptable and non-emptiness must be tracked at the type
96 * level.
97 *
98 * **Details**
99 *
100 * This is the mutable counterpart of {@link NonEmptyReadonlyArray}. Most Array
101 * module functions return `NonEmptyArray` when the result is guaranteed
102 * non-empty.
103 *
104 * **Example** (Typing a mutable non-empty array)
105 *
106 * ```ts import.meta.vitest
107 * import type { Array } from "effect"
108 *
109 * const nonEmpty: Array.NonEmptyArray<number> = [1, 2, 3]
110 * nonEmpty.push(4)
111 *
112 * nonEmpty // => [1, 2, 3, 4]
113 * ```
114 *
115 * @see {@link NonEmptyReadonlyArray} — readonly counterpart
116 * @see {@link isArrayNonEmpty} — narrow an `Array` to this type
117 *
118 * @category models
119 * @since 2.0.0
120 */
121export type NonEmptyArray<A> = [A, ...Array<A>]
122
123/**
124 * Creates a `NonEmptyArray` from one or more elements.
125 *
126 * **When to use**
127 *
128 * Use when you need to create a typed non-empty array from literal values.
129 *
130 * **Details**
131 *
132 * The element type is inferred as the union of all arguments. Because at least
133 * one argument is required, this always returns a `NonEmptyArray`.
134 *
135 * **Example** (Creating an array from values)
136 *
137 * ```ts import.meta.vitest
138 * import { Array } from "effect"
139 *
140 * Array.make(1, 2, 3) // => [1, 2, 3]
141 * ```
142 *
143 * @see {@link of} — create a single-element array
144 * @see {@link fromIterable} — create from any iterable
145 *
146 * @category constructors
147 * @since 2.0.0
148 */
149export const make = <Elements extends NonEmptyArray<unknown>>(
150 ...elements: Elements
151): NonEmptyArray<Elements[number]> => elements
152
153/**
154 * Creates a new `Array` of the specified length with all slots uninitialized.
155 *
156 * **When to use**
157 *
158 * Use when you need a pre-sized array that will be filled imperatively.
159 *
160 * **Details**
161 *
162 * `n` is rounded down. `NaN` and non-positive values are treated as `0`.
163 * Elements are typed as `A | undefined` because the slots are empty.
164 *
165 * **Example** (Allocating a fixed-size array)
166 *
167 * ```ts import.meta.vitest
168 * import { Array } from "effect"
169 *
170 * Array.allocate<number>(3).length // => 3
171 * ```
172 *
173 * @see {@link makeBy} — create an array by computing each element
174 *
175 * @category constructors
176 * @since 2.0.0
177 */
178export const allocate = <A = never>(n: number): Array<A | undefined> => new Array(Count.normalize(n))
179
180/**
181 * Creates a `NonEmptyArray` of length `n` where element `i` is computed by `f(i)`.
182 *
183 * **When to use**
184 *
185 * Use when you need to compute each array element from its index.
186 *
187 * **Details**
188 *
189 * `n` is rounded down and normalized to an integer greater than or equal to 1.
190 * `NaN` is treated as `1`, so this function always returns at least one
191 * element. Supports both data-first and data-last usage.
192 *
193 * **Example** (Generating values from indices)
194 *
195 * ```ts import.meta.vitest
196 * import { Array } from "effect"
197 *
198 * Array.makeBy(5, (n) => n * 2) // => [0, 2, 4, 6, 8]
199 * ```
200 *
201 * @see {@link range} — create a range of integers
202 * @see {@link replicate} — repeat a single value
203 *
204 * @category constructors
205 * @since 2.0.0
206 */
207export const makeBy: {
208 <A>(f: (i: number) => A): (n: number) => NonEmptyArray<A>
209 <A>(n: number, f: (i: number) => A): NonEmptyArray<A>
210} = dual(2, <A>(n: number, f: (i: number) => A) => {
211 const max = Count.normalizeNonEmpty(n)
212 const out = new Array(max)
213 for (let i = 0; i < max; i++) {
214 out[i] = f(i)
215 }
216 return out as NonEmptyArray<A>
217})
218
219/**
220 * Creates a `NonEmptyArray` containing a range of integers, inclusive on both
221 * ends.
222 *
223 * **When to use**
224 *
225 * Use when you need a non-empty sequence of consecutive integers.
226 *
227 * **Details**
228 *
229 * If `start > end`, returns `[start]`.
230 *
231 * **Example** (Creating a range)
232 *
233 * ```ts import.meta.vitest
234 * import { Array } from "effect"
235 *
236 * Array.range(1, 3) // => [1, 2, 3]
237 * ```
238 *
239 * @see {@link makeBy} — generate values from a function
240 *
241 * @category constructors
242 * @since 2.0.0
243 */
244export const range = (start: number, end: number): NonEmptyArray<number> =>
245 start <= end ? makeBy(end - start + 1, (i) => start + i) : [start]
246
247/**
248 * Creates a `NonEmptyArray` containing a value repeated `n` times.
249 *
250 * **When to use**
251 *
252 * Use when you need a non-empty array containing repeated copies of one value.
253 *
254 * **Details**
255 *
256 * `n` is normalized to an integer greater than or equal to 1, so this function
257 * always returns at least one element. Supports both data-first and data-last
258 * usage.
259 *
260 * **Example** (Repeating a value)
261 *
262 * ```ts import.meta.vitest
263 * import { Array } from "effect"
264 *
265 * Array.replicate("a", 3) // => ["a", "a", "a"]
266 * ```
267 *
268 * @see {@link makeBy} — vary values based on index
269 *
270 * @category constructors
271 * @since 2.0.0
272 */
273export const replicate: {
274 (n: number): <A>(a: A) => NonEmptyArray<A>
275 <A>(a: A, n: number): NonEmptyArray<A>
276} = dual(2, <A>(a: A, n: number): NonEmptyArray<A> => makeBy(n, () => a))
277
278/**
279 * Converts an `Iterable` to an `Array`.
280 *
281 * **When to use**
282 *
283 * Use to convert any `Iterable` (Set, Generator, etc.) into an array.
284 *
285 * **Details**
286 *
287 * If the input is already an array, this returns it by reference without
288 * copying. Otherwise, it creates a new array from the iterable. Use `copy` if
289 * you need a fresh array even when the input is already an array.
290 *
291 * **Example** (Converting a Set to an array)
292 *
293 * ```ts import.meta.vitest
294 * import { Array } from "effect"
295 *
296 * Array.fromIterable(new Set([1, 2, 3])) // => [1, 2, 3]
297 * ```
298 *
299 * @see {@link ensure} — wrap a single value or return an existing array
300 * @see {@link copy} — create a shallow copy of an array
301 *
302 * @category constructors
303 * @since 2.0.0
304 */
305export const fromIterable = <A>(collection: Iterable<A>): Array<A> =>
306 Array.isArray(collection) ? collection : Array.from(collection)
307
308/**
309 * Normalizes a value that is either a single element or an array into an array.
310 *
311 * **When to use**
312 *
313 * Use to normalize input that may be a single value or an array into a consistent
314 * array.
315 *
316 * **Details**
317 *
318 * If the input is already an array, this returns it by reference. If the input
319 * is a single value, this wraps it in a one-element array. This is useful for
320 * APIs that accept `A | Array<A>`.
321 *
322 * **Example** (Normalizing input)
323 *
324 * ```ts import.meta.vitest
325 * import { Array } from "effect"
326 *
327 * Array.ensure("a") // => ["a"]
328 * Array.ensure(["a", "b", "c"]) // => ["a", "b", "c"]
329 * ```
330 *
331 * @see {@link of} — always wrap in a single-element array
332 * @see {@link fromIterable} — convert any iterable
333 *
334 * @category constructors
335 * @since 3.3.0
336 */
337export const ensure = <A>(self: ReadonlyArray<A> | A): Array<A> => Array.isArray(self) ? self : [self as A]
338
339/**
340 * Converts a record into an array of `[key, value]` tuples.
341 *
342 * **When to use**
343 *
344 * Use to convert a record into an array of key-value tuples for iteration or
345 * transformation.
346 *
347 * **Details**
348 *
349 * Key order follows `Object.entries` semantics. Empty records produce an empty
350 * array.
351 *
352 * **Example** (Converting a record to entries)
353 *
354 * ```ts import.meta.vitest
355 * import { Array } from "effect"
356 *
357 * Array.fromRecord({ a: 1, b: 2, c: 3 }) // => [["a", 1], ["b", 2], ["c", 3]]
358 * ```
359 *
360 * @see {@link Record.toEntries} the equivalent function from the Record module
361 * @see {@link Record.fromEntries} to build a record from an array of tuples
362 *
363 * @category converting
364 * @since 2.0.0
365 */
366export const fromRecord: <K extends string, A>(self: Readonly<Record<K, A>>) => Array<[K, A]> = Record.toEntries
367
368/**
369 * Converts an `Option` to an array: `Some(a)` becomes `[a]`, `None` becomes `[]`.
370 *
371 * **When to use**
372 *
373 * Use to convert a single `Option` into an array for downstream array operations.
374 *
375 * **Example** (Converting an Option to an array)
376 *
377 * ```ts import.meta.vitest
378 * import { Array, Option } from "effect"
379 *
380 * Array.fromOption(Option.some(1)) // => [1]
381 * Array.fromOption(Option.none()) // => []
382 * ```
383 *
384 * @see {@link getSomes} — extract `Some` values from an array of Options
385 *
386 * @category converting
387 * @since 2.0.0
388 */
389export const fromOption: <A>(self: Option.Option<A>) => Array<A> = Option.toArray
390
391/**
392 * Pattern-matches on an array, handling empty and non-empty cases separately.
393 *
394 * **When to use**
395 *
396 * Use when you need to branch on whether an array is empty.
397 *
398 * **Details**
399 *
400 * `onNonEmpty` receives a `NonEmptyReadonlyArray`. Supports both data-first and
401 * data-last usage.
402 *
403 * **Example** (Branching on emptiness)
404 *
405 * ```ts import.meta.vitest
406 * import { Array } from "effect"
407 *
408 * const describe = Array.match({
409 * onEmpty: () => "empty",
410 * onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}`
411 * })
412 *
413 * describe([]) // => "empty"
414 * describe([1, 2, 3]) // => "head: 1, tail: 2"
415 * ```
416 *
417 * @see {@link matchLeft} — destructures into head + tail
418 * @see {@link matchRight} — destructures into init + last
419 *
420 * @category pattern matching
421 * @since 2.0.0
422 */
423export const match: {
424 <B, A, C = B>(
425 options: {
426 readonly onEmpty: LazyArg<B>
427 readonly onNonEmpty: (self: NonEmptyReadonlyArray<A>) => C
428 }
429 ): (self: ReadonlyArray<A>) => B | C
430 <A, B, C = B>(
431 self: ReadonlyArray<A>,
432 options: {
433 readonly onEmpty: LazyArg<B>
434 readonly onNonEmpty: (self: NonEmptyReadonlyArray<A>) => C
435 }
436 ): B | C
437} = dual(2, <A, B, C = B>(
438 self: ReadonlyArray<A>,
439 { onEmpty, onNonEmpty }: {
440 readonly onEmpty: LazyArg<B>
441 readonly onNonEmpty: (self: NonEmptyReadonlyArray<A>) => C
442 }
443): B | C => isReadonlyArrayNonEmpty(self) ? onNonEmpty(self) : onEmpty())
444
445/**
446 * Pattern-matches on an array from the left, providing the first element and
447 * the remaining elements separately.
448 *
449 * **When to use**
450 *
451 * Use when you need to branch on an array and handle the non-empty case as the
452 * first element plus the remaining elements.
453 *
454 * **Details**
455 *
456 * `onNonEmpty` receives `(head, tail)` where `tail` is the rest of the array.
457 *
458 * **Example** (Destructuring head and tail)
459 *
460 * ```ts import.meta.vitest
461 * import { Array } from "effect"
462 *
463 * const matchLeft = Array.matchLeft({
464 * onEmpty: () => "empty",
465 * onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}`
466 * })
467 *
468 * matchLeft([]) // => "empty"
469 * matchLeft([1, 2, 3]) // => "head: 1, tail: 2"
470 * ```
471 *
472 * @see {@link match} — receives the full non-empty array
473 * @see {@link matchRight} — destructures into init + last
474 *
475 * @category pattern matching
476 * @since 2.0.0
477 */
478export const matchLeft: {
479 <B, A, C = B>(
480 options: {
481 readonly onEmpty: LazyArg<B>
482 readonly onNonEmpty: (head: A, tail: Array<A>) => C
483 }
484 ): (self: ReadonlyArray<A>) => B | C
485 <A, B, C = B>(
486 self: ReadonlyArray<A>,
487 options: {
488 readonly onEmpty: LazyArg<B>
489 readonly onNonEmpty: (head: A, tail: Array<A>) => C
490 }
491 ): B | C
492} = dual(2, <A, B, C = B>(
493 self: ReadonlyArray<A>,
494 { onEmpty, onNonEmpty }: {
495 readonly onEmpty: LazyArg<B>
496 readonly onNonEmpty: (head: A, tail: Array<A>) => C
497 }
498): B | C => isReadonlyArrayNonEmpty(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty())
499
500/**
501 * Pattern-matches on an array from the right, providing all elements except the
502 * last and the last element separately.
503 *
504 * **When to use**
505 *
506 * Use when you need to branch on an array and handle the non-empty case as the
507 * elements before the last plus the last element.
508 *
509 * **Details**
510 *
511 * `onNonEmpty` receives `(init, last)` where `init` is everything but the last element.
512 *
513 * **Example** (Destructuring init and last)
514 *
515 * ```ts import.meta.vitest
516 * import { Array } from "effect"
517 *
518 * const matchRight = Array.matchRight({
519 * onEmpty: () => "empty",
520 * onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}`
521 * })
522 *
523 * matchRight([]) // => "empty"
524 * matchRight([1, 2, 3]) // => "init: 2, last: 3"
525 * ```
526 *
527 * @see {@link match} — receives the full non-empty array
528 * @see {@link matchLeft} — destructures into head + tail
529 *
530 * @category pattern matching
531 * @since 2.0.0
532 */
533export const matchRight: {
534 <B, A, C = B>(
535 options: {
536 readonly onEmpty: LazyArg<B>
537 readonly onNonEmpty: (init: Array<A>, last: A) => C
538 }
539 ): (self: ReadonlyArray<A>) => B | C
540 <A, B, C = B>(
541 self: ReadonlyArray<A>,
542 options: {
543 readonly onEmpty: LazyArg<B>
544 readonly onNonEmpty: (init: Array<A>, last: A) => C
545 }
546 ): B | C
547} = dual(2, <A, B, C = B>(
548 self: ReadonlyArray<A>,
549 { onEmpty, onNonEmpty }: {
550 readonly onEmpty: LazyArg<B>
551 readonly onNonEmpty: (init: Array<A>, last: A) => C
552 }
553): B | C =>
554 isReadonlyArrayNonEmpty(self) ?
555 onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) :
556 onEmpty())
557
558/**
559 * Adds a single element to the front of an iterable, returning a `NonEmptyArray`.
560 *
561 * **When to use**
562 *
563 * Use when you need to guarantee a non-empty result after adding a required
564 * leading value.
565 *
566 * **Example** (Prepending an element)
567 *
568 * ```ts import.meta.vitest
569 * import { Array } from "effect"
570 *
571 * Array.prepend([2, 3, 4], 1) // => [1, 2, 3, 4]
572 * ```
573 *
574 * @see {@link append} — add to the end
575 * @see {@link prependAll} — prepend multiple elements
576 *
577 * @category combining
578 * @since 2.0.0
579 */
580export const prepend: {
581 <B>(head: B): <A>(self: Iterable<A>) => NonEmptyArray<A | B>
582 <A, B>(self: Iterable<A>, head: B): NonEmptyArray<A | B>
583} = dual(2, <A, B>(self: Iterable<A>, head: B): NonEmptyArray<A | B> => [head, ...self])
584
585/**
586 * Prepends all elements from a prefix iterable to the front of an array.
587 *
588 * **When to use**
589 *
590 * Use to prepend multiple elements from an iterable to the front of an array.
591 *
592 * **Details**
593 *
594 * If either input is non-empty, the result is a `NonEmptyArray`.
595 *
596 * **Example** (Prepending multiple elements)
597 *
598 * ```ts import.meta.vitest
599 * import { Array } from "effect"
600 *
601 * Array.prependAll([2, 3], [0, 1]) // => [0, 1, 2, 3]
602 * ```
603 *
604 * @see {@link prepend} — add a single element to the front
605 * @see {@link appendAll} — add elements to the end
606 *
607 * @category combining
608 * @since 2.0.0
609 */
610export const prependAll: {
611 <S extends Iterable<any>, T extends Iterable<any>>(
612 that: T
613 ): (self: S) => ReadonlyArray.OrNonEmpty<S, T, ReadonlyArray.Infer<S> | ReadonlyArray.Infer<T>>
614 <A, B>(self: Iterable<A>, that: NonEmptyReadonlyArray<B>): NonEmptyArray<A | B>
615 <A, B>(self: NonEmptyReadonlyArray<A>, that: Iterable<B>): NonEmptyArray<A | B>
616 <A, B>(self: Iterable<A>, that: Iterable<B>): Array<A | B>
617} = dual(
618 2,
619 <A>(self: Iterable<A>, that: Iterable<A>): Array<A> => fromIterable(that).concat(fromIterable(self))
620)
621
622/**
623 * Adds a single element to the end of an iterable, returning a `NonEmptyArray`.
624 *
625 * **When to use**
626 *
627 * Use when you need to guarantee a non-empty result after adding a required
628 * trailing value.
629 *
630 * **Example** (Appending an element)
631 *
632 * ```ts import.meta.vitest
633 * import { Array } from "effect"
634 *
635 * Array.append([1, 2, 3], 4) // => [1, 2, 3, 4]
636 * ```
637 *
638 * @see {@link prepend} — add to the front
639 * @see {@link appendAll} — append multiple elements
640 *
641 * @category combining
642 * @since 2.0.0
643 */
644export const append: {
645 <B>(last: B): <A>(self: Iterable<A>) => NonEmptyArray<A | B>
646 <A, B>(self: Iterable<A>, last: B): NonEmptyArray<A | B>
647} = dual(2, <A, B>(self: Iterable<A>, last: B): Array<A | B> => [...self, last])
648
649/**
650 * Concatenates two iterables into a single array.
651 *
652 * **When to use**
653 *
654 * Use to combine two iterable inputs into a new array with the second input's
655 * elements after the first.
656 *
657 * **Details**
658 *
659 * If either input is non-empty, the result is a `NonEmptyArray`.
660 *
661 * **Example** (Concatenating arrays)
662 *
663 * ```ts import.meta.vitest
664 * import { Array } from "effect"
665 *
666 * Array.appendAll([1, 2], [3, 4]) // => [1, 2, 3, 4]
667 * ```
668 *
669 * @see {@link append} — add a single element to the end
670 * @see {@link prependAll} — add elements to the front
671 *
672 * @category combining
673 * @since 2.0.0
674 */
675export const appendAll: {
676 <S extends Iterable<any>, T extends Iterable<any>>(
677 that: T
678 ): (self: S) => ReadonlyArray.OrNonEmpty<S, T, ReadonlyArray.Infer<S> | ReadonlyArray.Infer<T>>
679 <A, B>(self: Iterable<A>, that: NonEmptyReadonlyArray<B>): NonEmptyArray<A | B>
680 <A, B>(self: NonEmptyReadonlyArray<A>, that: Iterable<B>): NonEmptyArray<A | B>
681 <A, B>(self: Iterable<A>, that: Iterable<B>): Array<A | B>
682} = dual(
683 2,
684 <A>(self: Iterable<A>, that: Iterable<A>): Array<A> => fromIterable(self).concat(fromIterable(that))
685)
686
687/**
688 * Folds left-to-right while keeping every intermediate accumulator value.
689 *
690 * **When to use**
691 *
692 * Use to compute a running accumulator where each intermediate value is needed.
693 *
694 * **Details**
695 *
696 * The output length is `input.length + 1` because it starts with the initial
697 * value. The result is always a `NonEmptyArray`. Use `reduce` if you only need
698 * the final accumulated value.
699 *
700 * **Example** (Running totals)
701 *
702 * ```ts import.meta.vitest
703 * import { Array } from "effect"
704 *
705 * Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value) // => [0, 1, 3, 6, 10]
706 * ```
707 *
708 * @see {@link scanRight} — right-to-left scan
709 * @see {@link reduce} — fold without intermediate values
710 *
711 * @category folding
712 * @since 2.0.0
713 */
714export const scan: {
715 <B, A>(b: B, f: (b: B, a: A) => B): (self: Iterable<A>) => NonEmptyArray<B>
716 <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): NonEmptyArray<B>
717} = dual(3, <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): NonEmptyArray<B> => {
718 const out: NonEmptyArray<B> = [b]
719 let i = 0
720 for (const a of self) {
721 out[i + 1] = f(out[i], a)
722 i++
723 }
724 return out
725})
726
727/**
728 * Folds right-to-left while keeping every intermediate accumulator value.
729 *
730 * **When to use**
731 *
732 * Use to compute a running accumulator from right to left where each intermediate
733 * value is needed.
734 *
735 * **Details**
736 *
737 * The output length is `input.length + 1` because it ends with the initial
738 * value. The result is always a `NonEmptyArray`.
739 *
740 * **Example** (Scanning running totals in reverse)
741 *
742 * ```ts import.meta.vitest
743 * import { Array } from "effect"
744 *
745 * Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value) // => [10, 9, 7, 4, 0]
746 * ```
747 *
748 * @see {@link scan} — left-to-right scan
749 * @see {@link reduceRight} — fold without intermediate values
750 *
751 * @category folding
752 * @since 2.0.0
753 */
754export const scanRight: {
755 <B, A>(b: B, f: (b: B, a: A) => B): (self: Iterable<A>) => NonEmptyArray<B>
756 <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): NonEmptyArray<B>
757} = dual(3, <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A) => B): NonEmptyArray<B> => {
758 const input = fromIterable(self)
759 const out: NonEmptyArray<B> = new Array(input.length + 1) as any
760 out[input.length] = b
761 for (let i = input.length - 1; i >= 0; i--) {
762 out[i] = f(out[i + 1], input[i])
763 }
764 return out
765})
766
767/**
768 * Checks whether a value is an `Array`.
769 *
770 * **When to use**
771 *
772 * Use to verify a value is a mutable array, narrowing its type to `Array<unknown>`.
773 *
774 * **Details**
775 *
776 * Acts as a type guard narrowing the input to `Array<unknown>` and delegates to
777 * `globalThis.Array.isArray`.
778 *
779 * **Example** (Type-guarding an unknown value)
780 *
781 * ```ts import.meta.vitest
782 * import { Array } from "effect"
783 *
784 * Array.isArray(null) // => false
785 * Array.isArray([1, 2, 3]) // => true
786 * ```
787 *
788 * @see {@link isArrayEmpty} — check for an empty array
789 * @see {@link isArrayNonEmpty} — check for a non-empty array
790 *
791 * @category guards
792 * @since 2.0.0
793 */
794export const isArray: {
795 (self: unknown): self is Array<unknown>
796 <T>(self: T): self is Extract<T, ReadonlyArray<any>>
797} = Array.isArray
798
799/**
800 * Checks whether a mutable `Array` is empty, narrowing the type to `[]`.
801 *
802 * **Example** (Checking for an empty array)
803 *
804 * ```ts import.meta.vitest
805 * import { Array } from "effect"
806 *
807 * Array.isArrayEmpty([]) // => true
808 * Array.isArrayEmpty([1, 2, 3]) // => false
809 * ```
810 *
811 * @see {@link isReadonlyArrayEmpty} — readonly variant
812 * @see {@link isArrayNonEmpty} — opposite check
813 *
814 * @category guards
815 * @since 4.0.0
816 */
817export const isArrayEmpty = <A>(self: Array<A>): self is [] => self.length === 0
818
819/**
820 * Checks whether a `ReadonlyArray` is empty, narrowing the type to `readonly []`.
821 *
822 * **Example** (Checking for an empty readonly array)
823 *
824 * ```ts import.meta.vitest
825 * import { Array } from "effect"
826 *
827 * Array.isReadonlyArrayEmpty([]) // => true
828 * Array.isReadonlyArrayEmpty([1, 2, 3]) // => false
829 * ```
830 *
831 * @see {@link isArrayEmpty} — mutable variant
832 * @see {@link isReadonlyArrayNonEmpty} — opposite check
833 *
834 * @category guards
835 * @since 4.0.0
836 */
837export const isReadonlyArrayEmpty: <A>(self: ReadonlyArray<A>) => self is readonly [] = isArrayEmpty as any
838
839/**
840 * Checks whether a mutable `Array` is non-empty, narrowing the type to
841 * `NonEmptyArray`.
842 *
843 * **When to use**
844 *
845 * Use when you need the narrowed value to remain a mutable `Array` after proving
846 * it has at least one element.
847 *
848 * **Example** (Checking for a non-empty array)
849 *
850 * ```ts import.meta.vitest
851 * import { Array } from "effect"
852 *
853 * Array.isArrayNonEmpty([]) // => false
854 * Array.isArrayNonEmpty([1, 2, 3]) // => true
855 * ```
856 *
857 * @see {@link isReadonlyArrayNonEmpty} — readonly variant
858 * @see {@link isArrayEmpty} — opposite check
859 *
860 * @category guards
861 * @since 4.0.0
862 */
863export const isArrayNonEmpty: <A>(self: Array<A>) => self is NonEmptyArray<A> = internalArray.isArrayNonEmpty
864
865/**
866 * Checks whether a `ReadonlyArray` is non-empty, narrowing the type to
867 * `NonEmptyReadonlyArray`.
868 *
869 * **When to use**
870 *
871 * Use when you need to prove a readonly array has at least one element without
872 * requiring mutable array methods afterward.
873 *
874 * **Example** (Checking for a non-empty readonly array)
875 *
876 * ```ts import.meta.vitest
877 * import { Array } from "effect"
878 *
879 * Array.isReadonlyArrayNonEmpty([]) // => false
880 * Array.isReadonlyArrayNonEmpty([1, 2, 3]) // => true
881 * ```
882 *
883 * @see {@link isArrayNonEmpty} — mutable variant
884 * @see {@link isReadonlyArrayEmpty} — opposite check
885 *
886 * @category guards
887 * @since 4.0.0
888 */
889export const isReadonlyArrayNonEmpty: <A>(self: ReadonlyArray<A>) => self is NonEmptyReadonlyArray<A> =
890 internalArray.isArrayNonEmpty
891
892/**
893 * Returns the number of elements in a `ReadonlyArray`.
894 *
895 * **When to use**
896 *
897 * Use when you need length as a composable function rather than a property access.
898 *
899 * **Example** (Getting the length)
900 *
901 * ```ts import.meta.vitest
902 * import { Array } from "effect"
903 *
904 * Array.length([1, 2, 3]) // => 3
905 * ```
906 *
907 * @category getters
908 * @since 2.0.0
909 */
910export const length = <A>(self: ReadonlyArray<A>): number => self.length
911
912/**
913 * Checks whether a string represents a JavaScript array index: a non-negative
914 * integer below `2 ** 32 - 1`, written without leading zeroes, a sign, or
915 * exponent notation.
916 *
917 * @internal
918 */
919export function isCanonicalArrayIndex(key: string): boolean {
920 const index = Number(key)
921 return String(index) === key && Number.isInteger(index) && index >= 0 && index < 2 ** 32 - 1
922}
923
924/** @internal */
925export function isOutOfBounds<A>(i: number, as: ReadonlyArray<A>): boolean {
926 return !Number.isFinite(i) || i < 0 || i >= as.length
927}
928
929/**
930 * Reads an element at the given index safely, returning `Option.some` or
931 * `Option.none` if the index is out of bounds.
932 *
933 * **When to use**
934 *
935 * Use when you need to read an array element by index and handle an
936 * out-of-bounds index as `Option.none`.
937 *
938 * **Details**
939 *
940 * The index is floored to an integer. This never throws.
941 *
942 * **Example** (Accessing indexes safely)
943 *
944 * ```ts import.meta.vitest
945 * import { Array, Option } from "effect"
946 *
947 * Array.get([1, 2, 3], 1) // => Option.some(2)
948 * Array.get([1, 2, 3], 10) // => Option.none()
949 * ```
950 *
951 * @see {@link getUnsafe} for indexed access that throws when the index is out of bounds
952 * @see {@link head} for reading the first element as an `Option`
953 * @see {@link last} for reading the last element as an `Option`
954 *
955 * @category getters
956 * @since 2.0.0
957 */
958export const get: {
959 (index: number): <A>(self: ReadonlyArray<A>) => Option.Option<A>
960 <A>(self: ReadonlyArray<A>, index: number): Option.Option<A>
961} = dual(2, <A>(self: ReadonlyArray<A>, index: number): Option.Option<A> => {
962 const i = Math.floor(index)
963 return isOutOfBounds(i, self) ? Option.none() : Option.some(self[i])
964})
965
966/**
967 * Reads an element at the given index, throwing if the index is out of bounds.
968 *
969 * **When to use**
970 *
971 * Use to read an array element at a known valid index when out-of-bounds would
972 * be a programming error.
973 *
974 * **Details**
975 *
976 * Throws an `Error` with the message `"Index out of bounds: <i>"`. Prefer
977 * `get` for safe access.
978 *
979 * **Example** (Accessing indexes unsafely)
980 *
981 * ```ts import.meta.vitest
982 * import { Array } from "effect"
983 *
984 * Array.getUnsafe([1, 2, 3], 1) // => 2
985 * // Array.getUnsafe([1, 2, 3], 10) // throws Error
986 * ```
987 *
988 * @see {@link get} — safe version returning `Option`
989 *
990 * @category unsafe
991 * @since 4.0.0
992 */
993export const getUnsafe: {
994 (index: number): <A>(self: ReadonlyArray<A>) => A
995 <A>(self: ReadonlyArray<A>, index: number): A
996} = dual(2, <A>(self: ReadonlyArray<A>, index: number): A => {
997 const i = Math.floor(index)
998 if (isOutOfBounds(i, self)) {
999 throw new Error(`Index out of bounds: ${i}`)
1000 }
1001 return self[i]
1002})
1003
1004/**
1005 * Splits a non-empty array into its first element and the remaining elements.
1006 *
1007 * **When to use**
1008 *
1009 * Use when you have a `NonEmptyReadonlyArray` and need both its first element
1010 * and the remaining elements as separate values.
1011 *
1012 * **Details**
1013 *
1014 * Returns a tuple `[head, tail]` and requires a `NonEmptyReadonlyArray`.
1015 *
1016 * **Example** (Destructuring head and tail)
1017 *
1018 * ```ts import.meta.vitest
1019 * import { Array } from "effect"
1020 *
1021 * Array.unprepend([1, 2, 3, 4]) // => [1, [2, 3, 4]]
1022 * ```
1023 *
1024 * @see {@link unappend} for splitting a non-empty array into init and last
1025 * @see {@link headNonEmpty} for getting only the first element
1026 * @see {@link tailNonEmpty} for getting only the elements after the first
1027 *
1028 * @category splitting
1029 * @since 2.0.0
1030 */
1031export const unprepend = <A>(
1032 self: NonEmptyReadonlyArray<A>
1033): [firstElement: A, remainingElements: Array<A>] => [headNonEmpty(self), tailNonEmpty(self)]
1034
1035/**
1036 * Splits a non-empty array into all elements except the last, and the last
1037 * element.
1038 *
1039 * **When to use**
1040 *
1041 * Use when you need to split a non-empty array into the elements before the
1042 * last element and the last element.
1043 *
1044 * **Details**
1045 *
1046 * Returns a tuple `[init, last]` and requires a `NonEmptyReadonlyArray`.
1047 *
1048 * **Example** (Destructuring init and last)
1049 *
1050 * ```ts import.meta.vitest
1051 * import { Array } from "effect"
1052 *
1053 * Array.unappend([1, 2, 3, 4]) // => [[1, 2, 3], 4]
1054 * ```
1055 *
1056 * @see {@link unprepend} for splitting a non-empty array into head and tail
1057 * @see {@link initNonEmpty} for getting only the elements before the last
1058 * @see {@link lastNonEmpty} for getting only the last element
1059 *
1060 * @category splitting
1061 * @since 2.0.0
1062 */
1063export const unappend = <A>(
1064 self: NonEmptyReadonlyArray<A>
1065): [arrayWithoutLastElement: Array<A>, lastElement: A] => [initNonEmpty(self), lastNonEmpty(self)]
1066
1067/**
1068 * Returns the first element of an array safely wrapped in `Option.some`, or
1069 * `Option.none` if the array is empty.
1070 *
1071 * **When to use**
1072 *
1073 * Use to safely get the first element of an array that may be empty.
1074 *
1075 * **Example** (Getting the first element)
1076 *
1077 * ```ts import.meta.vitest
1078 * import { Array, Option } from "effect"
1079 *
1080 * Array.head([1, 2, 3]) // => Option.some(1)
1081 * Array.head([]) // => Option.none()
1082 * ```
1083 *
1084 * @see {@link headNonEmpty} — direct access when array is known non-empty
1085 * @see {@link last} — get the last element
1086 *
1087 * @category getters
1088 * @since 2.0.0
1089 */
1090export const head: <A>(self: ReadonlyArray<A>) => Option.Option<A> = get(0)
1091
1092/**
1093 * Returns the first element of a `NonEmptyReadonlyArray` directly (no `Option`
1094 * wrapper).
1095 *
1096 * **When to use**
1097 *
1098 * Use to get the first element without `Option` wrapping when the array is known
1099 * to be non-empty.
1100 *
1101 * **Example** (Getting the head of a non-empty array)
1102 *
1103 * ```ts import.meta.vitest
1104 * import { Array } from "effect"
1105 *
1106 * Array.headNonEmpty([1, 2, 3, 4]) // => 1
1107 * ```
1108 *
1109 * @see {@link head} — safe version for possibly-empty arrays
1110 *
1111 * @category getters
1112 * @since 2.0.0
1113 */
1114export const headNonEmpty: <A>(self: NonEmptyReadonlyArray<A>) => A = getUnsafe(0)
1115
1116/**
1117 * Returns the last element of an array safely wrapped in `Option.some`, or
1118 * `Option.none` if the array is empty.
1119 *
1120 * **When to use**
1121 *
1122 * Use to safely get the last element of an array that may be empty.
1123 *
1124 * **Example** (Getting the last element)
1125 *
1126 * ```ts import.meta.vitest
1127 * import { Array, Option } from "effect"
1128 *
1129 * Array.last([1, 2, 3]) // => Option.some(3)
1130 * Array.last([]) // => Option.none()
1131 * ```
1132 *
1133 * @see {@link lastNonEmpty} — direct access when array is known non-empty
1134 * @see {@link head} — get the first element
1135 *
1136 * @category getters
1137 * @since 2.0.0
1138 */
1139export const last = <A>(self: ReadonlyArray<A>): Option.Option<A> =>
1140 isReadonlyArrayNonEmpty(self) ? Option.some(lastNonEmpty(self)) : Option.none()
1141
1142/**
1143 * Returns the last element of a `NonEmptyReadonlyArray` directly (no `Option`
1144 * wrapper).
1145 *
1146 * **When to use**
1147 *
1148 * Use to get the last element without `Option` wrapping when the array is known
1149 * to be non-empty.
1150 *
1151 * **Example** (Getting the last of a non-empty array)
1152 *
1153 * ```ts import.meta.vitest
1154 * import { Array } from "effect"
1155 *
1156 * Array.lastNonEmpty([1, 2, 3, 4]) // => 4
1157 * ```
1158 *
1159 * @see {@link last} — safe version for possibly-empty arrays
1160 *
1161 * @category getters
1162 * @since 2.0.0
1163 */
1164export const lastNonEmpty = <A>(self: NonEmptyReadonlyArray<A>): A => self[self.length - 1]
1165
1166/**
1167 * Returns all elements except the first safely, wrapped in an `Option`.
1168 *
1169 * **When to use**
1170 *
1171 * Use to safely get all elements after the first when the iterable may be empty.
1172 *
1173 * **Details**
1174 *
1175 * Allocates a new array via `slice(1)`. Empty inputs return `Option.none()`.
1176 *
1177 * **Example** (Getting the tail)
1178 *
1179 * ```ts import.meta.vitest
1180 * import { Array, Option } from "effect"
1181 *
1182 * Array.tail([1, 2, 3, 4]) // => Option.some([2, 3, 4])
1183 * Array.tail([]) // => Option.none()
1184 * ```
1185 *
1186 * @see {@link tailNonEmpty} — when the array is known non-empty
1187 * @see {@link init} — all elements except the last
1188 *
1189 * @category getters
1190 * @since 2.0.0
1191 */
1192export function tail<A>(self: Iterable<A>): Option.Option<Array<A>> {
1193 const as = fromIterable(self)
1194 return isReadonlyArrayNonEmpty(as) ? Option.some(tailNonEmpty(as)) : Option.none()
1195}
1196
1197/**
1198 * Returns all elements except the first of a `NonEmptyReadonlyArray`.
1199 *
1200 * **When to use**
1201 *
1202 * Use to get all elements after the first when the array is known to be non-empty.
1203 *
1204 * **Example** (Getting the tail of a non-empty array)
1205 *
1206 * ```ts import.meta.vitest
1207 * import { Array } from "effect"
1208 *
1209 * Array.tailNonEmpty([1, 2, 3, 4]) // => [2, 3, 4]
1210 * ```
1211 *
1212 * @see {@link tail} — safe version for possibly-empty arrays
1213 * @see {@link initNonEmpty} — all elements except the last
1214 *
1215 * @category getters
1216 * @since 2.0.0
1217 */
1218export const tailNonEmpty = <A>(self: NonEmptyReadonlyArray<A>): Array<A> => self.slice(1)
1219
1220/**
1221 * Returns all elements except the last safely, wrapped in an `Option`.
1222 *
1223 * **When to use**
1224 *
1225 * Use to safely get all elements before the last when the iterable may be empty.
1226 *
1227 * **Details**
1228 *
1229 * Allocates a new array via `slice(0, -1)`. Empty inputs return
1230 * `Option.none()`.
1231 *
1232 * **Example** (Getting init)
1233 *
1234 * ```ts import.meta.vitest
1235 * import { Array, Option } from "effect"
1236 *
1237 * Array.init([1, 2, 3, 4]) // => Option.some([1, 2, 3])
1238 * Array.init([]) // => Option.none()
1239 * ```
1240 *
1241 * @see {@link initNonEmpty} — when the array is known non-empty
1242 * @see {@link tail} — all elements except the first
1243 *
1244 * @category getters
1245 * @since 2.0.0
1246 */
1247export function init<A>(self: Iterable<A>): Option.Option<Array<A>> {
1248 const as = fromIterable(self)
1249 return isReadonlyArrayNonEmpty(as) ? Option.some(initNonEmpty(as)) : Option.none()
1250}
1251
1252/**
1253 * Returns all elements except the last of a `NonEmptyReadonlyArray`.
1254 *
1255 * **When to use**
1256 *
1257 * Use to get all elements before the last when the array is known to be non-empty.
1258 *
1259 * **Example** (Getting init of a non-empty array)
1260 *
1261 * ```ts import.meta.vitest
1262 * import { Array } from "effect"
1263 *
1264 * Array.initNonEmpty([1, 2, 3, 4]) // => [1, 2, 3]
1265 * ```
1266 *
1267 * @see {@link init} — safe version for possibly-empty arrays
1268 * @see {@link tailNonEmpty} — all elements except the first
1269 *
1270 * @category getters
1271 * @since 2.0.0
1272 */
1273export const initNonEmpty = <A>(self: NonEmptyReadonlyArray<A>): Array<A> => self.slice(0, -1)
1274
1275const clampCount = (n: number, length: number): number => Math.min(Count.normalize(n), length)
1276
1277/**
1278 * Keeps the first `n` elements, creating a new array.
1279 *
1280 * **When to use**
1281 *
1282 * Use to keep up to the first `n` elements from an iterable as a new array.
1283 *
1284 * **Details**
1285 *
1286 * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`.
1287 * Returns an empty array when `n <= 0`.
1288 *
1289 * **Example** (Taking from the start)
1290 *
1291 * ```ts import.meta.vitest
1292 * import { Array } from "effect"
1293 *
1294 * Array.take([1, 2, 3, 4, 5], 3) // => [1, 2, 3]
1295 * ```
1296 *
1297 * @see {@link takeRight} for keeping elements from the end
1298 * @see {@link takeWhile} for keeping an initial prefix while a predicate holds
1299 * @see {@link drop} for removing elements from the start
1300 *
1301 * @category getters
1302 * @since 2.0.0
1303 */
1304export const take: {
1305 (n: number): <A>(self: Iterable<A>) => Array<A>
1306 <A>(self: Iterable<A>, n: number): Array<A>
1307} = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => {
1308 const input = fromIterable(self)
1309 return input.slice(0, clampCount(n, input.length))
1310})
1311
1312/**
1313 * Keeps the last `n` elements, creating a new array.
1314 *
1315 * **When to use**
1316 *
1317 * Use to keep the last `n` elements of an iterable.
1318 *
1319 * **Details**
1320 *
1321 * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`.
1322 * Returns an empty array when `n <= 0`.
1323 *
1324 * **Example** (Taking from the end)
1325 *
1326 * ```ts import.meta.vitest
1327 * import { Array } from "effect"
1328 *
1329 * Array.takeRight([1, 2, 3, 4, 5], 3) // => [3, 4, 5]
1330 * ```
1331 *
1332 * @see {@link take} — keep from the start
1333 * @see {@link dropRight} — remove from the end
1334 *
1335 * @category getters
1336 * @since 2.0.0
1337 */
1338export const takeRight: {
1339 (n: number): <A>(self: Iterable<A>) => Array<A>
1340 <A>(self: Iterable<A>, n: number): Array<A>
1341} = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => {
1342 const input = fromIterable(self)
1343 const i = clampCount(n, input.length)
1344 return i === 0 ? [] : input.slice(-i)
1345})
1346
1347/**
1348 * Takes elements from the start while the predicate holds, stopping at the
1349 * first element that fails.
1350 *
1351 * **When to use**
1352 *
1353 * Use to keep the leading elements of an iterable while each element satisfies
1354 * a predicate, returning the retained prefix as an array.
1355 *
1356 * **Details**
1357 *
1358 * Supports refinements for type narrowing. The predicate receives
1359 * `(element, index)`.
1360 *
1361 * **Example** (Taking while condition holds)
1362 *
1363 * ```ts import.meta.vitest
1364 * import { Array } from "effect"
1365 *
1366 * Array.takeWhile([1, 3, 2, 4, 1, 2], (x) => x < 4) // => [1, 3, 2]
1367 * ```
1368 *
1369 * @see {@link take} for keeping a fixed number of leading elements
1370 * @see {@link dropWhile} for removing the matching prefix and keeping the rest
1371 * @see {@link span} for splitting the matching prefix from the remaining elements
1372 *
1373 * @category getters
1374 * @since 2.0.0
1375 */
1376export const takeWhile: {
1377 <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Array<B>
1378 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Array<A>
1379 <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Array<B>
1380 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A>
1381} = dual(2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A> => {
1382 let i = 0
1383 const out: Array<A> = []
1384 for (const a of self) {
1385 if (!predicate(a, i)) {
1386 break
1387 }
1388 out.push(a)
1389 i++
1390 }
1391 return out
1392})
1393
1394/**
1395 * Takes elements from the start while a `Filter` succeeds, collecting transformed values.
1396 *
1397 * **When to use**
1398 *
1399 * Use when you need to take a prefix from an iterable while a function can
1400 * successfully extract or transform elements, stopping at the first element
1401 * that produces a failure result.
1402 *
1403 * **Details**
1404 *
1405 * The filter receives `(element, index)` and processing stops at the first
1406 * filter failure.
1407 *
1408 * @see {@link takeWhile} for taking a prefix based on a boolean predicate
1409 *
1410 * @category getters
1411 * @since 4.0.0
1412 */
1413export const takeWhileFilter: {
1414 <A, B, X>(f: (input: NoInfer<A>, i: number) => Result.Result<B, X>): (self: Iterable<A>) => Array<B>
1415 <A, B, X>(self: Iterable<A>, f: (input: NoInfer<A>, i: number) => Result.Result<B, X>): Array<B>
1416} = dual(2, <A, B, X>(self: Iterable<A>, f: (input: NoInfer<A>, i: number) => Result.Result<B, X>): Array<B> => {
1417 let i = 0
1418 const out: Array<B> = []
1419 for (const a of self) {
1420 const result = f(a, i)
1421 if (Result.isFailure(result)) {
1422 break
1423 }
1424 out.push(result.success)
1425 i++
1426 }
1427 return out
1428})
1429
1430const spanIndex = <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): number => {
1431 let i = 0
1432 for (const a of self) {
1433 if (!predicate(a, i)) {
1434 break
1435 }
1436 i++
1437 }
1438 return i
1439}
1440
1441/**
1442 * Splits an iterable into two arrays: the longest prefix where the predicate
1443 * holds, and the remaining elements.
1444 *
1445 * **When to use**
1446 *
1447 * Use when you need both the longest predicate-matching prefix and the
1448 * remaining elements.
1449 *
1450 * **Details**
1451 *
1452 * Equivalent to `[takeWhile(pred), dropWhile(pred)]`, but more efficient
1453 * because it runs in a single pass. Supports refinements for type narrowing of
1454 * the prefix.
1455 *
1456 * **Example** (Splitting at predicate boundary)
1457 *
1458 * ```ts import.meta.vitest
1459 * import { Array } from "effect"
1460 *
1461 * Array.span([1, 3, 2, 4, 5], (x) => x % 2 === 1) // => [[1, 3], [2, 4, 5]]
1462 * ```
1463 *
1464 * @see {@link takeWhile} for keeping only the matching prefix
1465 * @see {@link dropWhile} for keeping only the elements after the matching prefix
1466 * @see {@link splitWhere} for splitting at the first element that satisfies a predicate
1467 *
1468 * @category splitting
1469 * @since 2.0.0
1470 */
1471export const span: {
1472 <A, B extends A>(
1473 refinement: (a: NoInfer<A>, i: number) => a is B
1474 ): (self: Iterable<A>) => [init: Array<B>, rest: Array<Exclude<A, B>>]
1475 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => [init: Array<A>, rest: Array<A>]
1476 <A, B extends A>(
1477 self: Iterable<A>,
1478 refinement: (a: A, i: number) => a is B
1479 ): [init: Array<B>, rest: Array<Exclude<A, B>>]
1480 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): [init: Array<A>, rest: Array<A>]
1481} = dual(
1482 2,
1483 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): [init: Array<A>, rest: Array<A>] => {
1484 const input = fromIterable(self)
1485 return splitAt(input, spanIndex(input, predicate))
1486 }
1487)
1488
1489/**
1490 * Removes the first `n` elements, creating a new array.
1491 *
1492 * **When to use**
1493 *
1494 * Use to keep the suffix of an iterable after skipping a fixed number of
1495 * leading elements.
1496 *
1497 * **Details**
1498 *
1499 * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`.
1500 * When `n <= 0`, this returns a copy of the full array.
1501 *
1502 * **Example** (Dropping from the start)
1503 *
1504 * ```ts import.meta.vitest
1505 * import { Array } from "effect"
1506 *
1507 * Array.drop([1, 2, 3, 4, 5], 2) // => [3, 4, 5]
1508 * ```
1509 *
1510 * @see {@link dropRight} for removing a fixed number of elements from the end
1511 * @see {@link dropWhile} for removing a prefix based on a predicate instead of a fixed count
1512 * @see {@link take} for keeping a fixed number of elements from the start
1513 *
1514 * @category getters
1515 * @since 2.0.0
1516 */
1517export const drop: {
1518 (n: number): <A>(self: Iterable<A>) => Array<A>
1519 <A>(self: Iterable<A>, n: number): Array<A>
1520} = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => {
1521 const input = fromIterable(self)
1522 return input.slice(clampCount(n, input.length), input.length)
1523})
1524
1525/**
1526 * Removes the last `n` elements, creating a new array.
1527 *
1528 * **When to use**
1529 *
1530 * Use to remove the last `n` elements from an iterable.
1531 *
1532 * **Details**
1533 *
1534 * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`.
1535 *
1536 * **Example** (Dropping from the end)
1537 *
1538 * ```ts import.meta.vitest
1539 * import { Array } from "effect"
1540 *
1541 * Array.dropRight([1, 2, 3, 4, 5], 2) // => [1, 2, 3]
1542 * ```
1543 *
1544 * @see {@link drop} — remove from the start
1545 * @see {@link takeRight} — keep from the end
1546 *
1547 * @category getters
1548 * @since 2.0.0
1549 */
1550export const dropRight: {
1551 (n: number): <A>(self: Iterable<A>) => Array<A>
1552 <A>(self: Iterable<A>, n: number): Array<A>
1553} = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => {
1554 const input = fromIterable(self)
1555 return input.slice(0, input.length - clampCount(n, input.length))
1556})
1557
1558/**
1559 * Drops elements from the start while the predicate holds, returning the rest.
1560 *
1561 * **When to use**
1562 *
1563 * Use to remove a leading prefix of elements that satisfy a predicate.
1564 *
1565 * **Details**
1566 *
1567 * The predicate receives `(element, index)`.
1568 *
1569 * **Example** (Dropping while condition holds)
1570 *
1571 * ```ts import.meta.vitest
1572 * import { Array } from "effect"
1573 *
1574 * Array.dropWhile([1, 2, 3, 4, 5], (x) => x < 4) // => [4, 5]
1575 * ```
1576 *
1577 * @see {@link takeWhile} — keep the matching prefix instead
1578 * @see {@link drop} — drop a fixed count
1579 *
1580 * @category getters
1581 * @since 2.0.0
1582 */
1583export const dropWhile: {
1584 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Array<A>
1585 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A>
1586} = dual(2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A> => {
1587 const input = fromIterable(self)
1588 let i = 0
1589 while (i < input.length) {
1590 if (!predicate(input[i], i)) {
1591 break
1592 }
1593 i++
1594 }
1595 return input.slice(i)
1596})
1597
1598/**
1599 * Drops elements from the start while a `Filter` succeeds.
1600 *
1601 * **When to use**
1602 *
1603 * Use when you need to drop a prefix from an iterable by computing a `Result`
1604 * per element instead of using a simple boolean predicate.
1605 *
1606 * **Details**
1607 *
1608 * The filter receives `(element, index)`. The result contains the remaining
1609 * original elements after the first filter failure.
1610 *
1611 * @see {@link dropWhile} for dropping a prefix with a simple boolean predicate
1612 * @see {@link takeWhileFilter} for keeping only the matching prefix
1613 *
1614 * @category getters
1615 * @since 4.0.0
1616 */
1617export const dropWhileFilter: {
1618 <A, B, X>(f: (input: NoInfer<A>, i: number) => Result.Result<B, X>): (self: Iterable<A>) => Array<A>
1619 <A, B, X>(self: Iterable<A>, f: (input: A, i: number) => Result.Result<B, X>): Array<A>
1620} = dual(
1621 2,
1622 <A, B, X>(self: Iterable<A>, f: (input: A, i: number) => Result.Result<B, X>): Array<A> => {
1623 const input = fromIterable(self)
1624 let i = 0
1625 while (i < input.length) {
1626 if (Result.isFailure(f(input[i], i))) {
1627 break
1628 }
1629 i++
1630 }
1631 return input.slice(i)
1632 }
1633)
1634
1635/**
1636 * Returns the index of the first element matching the predicate, wrapped in an
1637 * `Option`.
1638 *
1639 * **When to use**
1640 *
1641 * Use to find the index of the first matching element from the start of an
1642 * iterable.
1643 *
1644 * **Example** (Finding an index)
1645 *
1646 * ```ts import.meta.vitest
1647 * import { Array, Option } from "effect"
1648 *
1649 * Array.findFirstIndex([5, 3, 8, 9], (x) => x > 5) // => Option.some(2)
1650 * ```
1651 *
1652 * @see {@link findLastIndex} — search from the end
1653 * @see {@link findFirst} — get the element itself
1654 *
1655 * @category searching
1656 * @since 2.0.0
1657 */
1658export const findFirstIndex: {
1659 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option.Option<number>
1660 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<number>
1661} = dual(2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<number> => {
1662 let i = 0
1663 for (const a of self) {
1664 if (predicate(a, i)) {
1665 return Option.some(i)
1666 }
1667 i++
1668 }
1669 return Option.none()
1670})
1671
1672/**
1673 * Returns the index of the last element matching the predicate, wrapped in an
1674 * `Option`.
1675 *
1676 * **When to use**
1677 *
1678 * Use to find the index of the last matching element from the end of an array.
1679 *
1680 * **Example** (Finding the last matching index)
1681 *
1682 * ```ts import.meta.vitest
1683 * import { Array, Option } from "effect"
1684 *
1685 * Array.findLastIndex([1, 3, 8, 9], (x) => x < 5) // => Option.some(1)
1686 * ```
1687 *
1688 * @see {@link findFirstIndex} — search from the start
1689 * @see {@link findLast} — get the element itself
1690 *
1691 * @category searching
1692 * @since 2.0.0
1693 */
1694export const findLastIndex: {
1695 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option.Option<number>
1696 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<number>
1697} = dual(2, <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<number> => {
1698 const input = fromIterable(self)
1699 for (let i = input.length - 1; i >= 0; i--) {
1700 if (predicate(input[i], i)) {
1701 return Option.some(i)
1702 }
1703 }
1704 return Option.none()
1705})
1706
1707/**
1708 * Returns the first element matching a predicate, refinement, or mapping
1709 * function, wrapped in `Option`.
1710 *
1711 * **When to use**
1712 *
1713 * Use to scan an iterable in iteration order and return the first selected
1714 * element or mapped value as an `Option`.
1715 *
1716 * **Details**
1717 *
1718 * Accepts a predicate `(a, i) => boolean`, a refinement, or a function
1719 * `(a, i) => Option<B>` for simultaneous find-and-transform. If no element
1720 * matches, this returns `Option.none()`.
1721 *
1722 * **Example** (Finding the first match)
1723 *
1724 * ```ts import.meta.vitest
1725 * import { Array, Option } from "effect"
1726 *
1727 * Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3) // => Option.some(4)
1728 * ```
1729 *
1730 * @see {@link findLast} — search from the end
1731 * @see {@link findFirstIndex} — get the index instead
1732 * @see {@link findFirstWithIndex} — get both element and index
1733 *
1734 * @category searching
1735 * @since 2.0.0
1736 */
1737export const findFirst: {
1738 <A, B>(f: (a: NoInfer<A>, i: number) => Option.Option<B>): (self: Iterable<A>) => Option.Option<B>
1739 <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Option.Option<B>
1740 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option.Option<A>
1741 <A, B>(self: Iterable<A>, f: (a: A, i: number) => Option.Option<B>): Option.Option<B>
1742 <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Option.Option<B>
1743 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<A>
1744} = moduleIterable.findFirst
1745
1746/**
1747 * Returns the first selected value together with its index, wrapped in an
1748 * `Option`.
1749 *
1750 * **When to use**
1751 *
1752 * Use to find both the first matching element and its index in one pass.
1753 *
1754 * **Details**
1755 *
1756 * Accepts a predicate, a refinement, or a function returning `Option`. For an
1757 * `Option`-returning function, returns `[mappedValue, index]` for the first
1758 * `Some`, or `Option.none()` if no element is selected.
1759 *
1760 * **Example** (Finding element with its index)
1761 *
1762 * ```ts import.meta.vitest
1763 * import { Array, Option } from "effect"
1764 *
1765 * Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3) // => Option.some([4, 3])
1766 * ```
1767 *
1768 * @see {@link findFirst} — get only the element
1769 * @see {@link findFirstIndex} — get only the index
1770 *
1771 * @category searching
1772 * @since 3.17.0
1773 */
1774export const findFirstWithIndex: {
1775 <A, B>(f: (a: NoInfer<A>, i: number) => Option.Option<B>): (self: Iterable<A>) => Option.Option<[B, number]>
1776 <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Option.Option<[B, number]>
1777 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option.Option<[A, number]>
1778 <A, B>(self: Iterable<A>, f: (a: A, i: number) => Option.Option<B>): Option.Option<[B, number]>
1779 <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Option.Option<[B, number]>
1780 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<[A, number]>
1781} = dual(
1782 2,
1783 <A>(
1784 self: Iterable<A>,
1785 f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option.Option<A>)
1786 ): Option.Option<[A, number]> => {
1787 let i = 0
1788 for (const a of self) {
1789 const o = f(a, i)
1790 if (typeof o === "boolean") {
1791 if (o) {
1792 return Option.some([a, i])
1793 }
1794 } else {
1795 if (Option.isSome(o)) {
1796 return Option.some([o.value, i])
1797 }
1798 }
1799 i++
1800 }
1801 return Option.none()
1802 }
1803)
1804
1805/**
1806 * Returns the last element matching a predicate, refinement, or mapping
1807 * function, wrapped in `Option`.
1808 *
1809 * **When to use**
1810 *
1811 * Use to find the last matching element from the end of an array.
1812 *
1813 * **Details**
1814 *
1815 * Searches from the end of the array. If no element matches, this returns
1816 * `Option.none()`.
1817 *
1818 * **Example** (Finding the last match)
1819 *
1820 * ```ts import.meta.vitest
1821 * import { Array, Option } from "effect"
1822 *
1823 * Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0) // => Option.some(4)
1824 * ```
1825 *
1826 * @see {@link findFirst} — search from the start
1827 * @see {@link findLastIndex} — get the index instead
1828 *
1829 * @category searching
1830 * @since 2.0.0
1831 */
1832export const findLast: {
1833 <A, B>(f: (a: NoInfer<A>, i: number) => Option.Option<B>): (self: Iterable<A>) => Option.Option<B>
1834 <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Option.Option<B>
1835 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Option.Option<A>
1836 <A, B>(self: Iterable<A>, f: (a: A, i: number) => Option.Option<B>): Option.Option<B>
1837 <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Option.Option<B>
1838 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Option.Option<A>
1839} = dual(
1840 2,
1841 <A>(
1842 self: Iterable<A>,
1843 f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option.Option<A>)
1844 ): Option.Option<A> => {
1845 const input = fromIterable(self)
1846 for (let i = input.length - 1; i >= 0; i--) {
1847 const a = input[i]
1848 const o = f(a, i)
1849 if (typeof o === "boolean") {
1850 if (o) {
1851 return Option.some(a)
1852 }
1853 } else {
1854 if (Option.isSome(o)) {
1855 return o
1856 }
1857 }
1858 }
1859 return Option.none()
1860 }
1861)
1862
1863/**
1864 * Inserts an element at the specified index safely, returning a new `NonEmptyArray`
1865 * wrapped in an `Option`.
1866 *
1867 * **When to use**
1868 *
1869 * Use to insert a single element at a specific position in an array.
1870 *
1871 * **Details**
1872 *
1873 * Valid indices are `0` to `length`, inclusive. Inserting at `length` appends.
1874 *
1875 * **Example** (Inserting at an index)
1876 *
1877 * ```ts import.meta.vitest
1878 * import { Array, Option } from "effect"
1879 *
1880 * Array.insertAt(["a", "b", "c", "e"], 3, "d") // => Option.some(["a", "b", "c", "d", "e"])
1881 * ```
1882 *
1883 * @see {@link replace} — replace an existing element
1884 * @see {@link modify} — transform an element at an index
1885 *
1886 * @category transforming
1887 * @since 2.0.0
1888 */
1889export const insertAt: {
1890 <B>(i: number, b: B): <A>(self: Iterable<A>) => Option.Option<NonEmptyArray<A | B>>
1891 <A, B>(self: Iterable<A>, i: number, b: B): Option.Option<NonEmptyArray<A | B>>
1892} = dual(3, <A, B>(self: Iterable<A>, i: number, b: B): Option.Option<NonEmptyArray<A | B>> => {
1893 const out: Array<A | B> = Array.from(self) // copy because `splice` mutates the array
1894 const index = Math.floor(i)
1895 if (index !== out.length && isOutOfBounds(index, out)) {
1896 return Option.none()
1897 }
1898 out.splice(index, 0, b)
1899 return Option.some(out as any)
1900})
1901
1902/**
1903 * Replaces the element at the specified index safely with a new value, returning the
1904 * updated array in `Option.some`.
1905 *
1906 * **When to use**
1907 *
1908 * Use to set a fixed replacement value at a specific index.
1909 *
1910 * **Details**
1911 *
1912 * Returns `Option.none()` when the index is out of bounds.
1913 *
1914 * **Example** (Replacing an element)
1915 *
1916 * ```ts import.meta.vitest
1917 * import { Array, Option } from "effect"
1918 *
1919 * Array.replace([1, 2, 3], 1, 4) // => Option.some([1, 4, 3])
1920 * ```
1921 *
1922 * @see {@link modify} — transform an element with a function
1923 * @see {@link insertAt} — insert without removing
1924 *
1925 * @category transforming
1926 * @since 2.0.0
1927 */
1928export const replace: {
1929 <B>(i: number, b: B): <A, S extends Iterable<A> = Iterable<A>>(
1930 self: S
1931 ) => Option.Option<ReadonlyArray.With<S, ReadonlyArray.Infer<S> | B>>
1932 <A, B, S extends Iterable<A> = Iterable<A>>(
1933 self: S,
1934 i: number,
1935 b: B
1936 ): Option.Option<ReadonlyArray.With<S, ReadonlyArray.Infer<S> | B>>
1937} = dual(
1938 3,
1939 <A, B>(self: Iterable<A>, i: number, b: B): Option.Option<Array<A | B>> => modify(self, i, () => b)
1940)
1941
1942/**
1943 * Applies a function to the element at the specified index safely, returning the
1944 * updated array in `Option.some`.
1945 *
1946 * **When to use**
1947 *
1948 * Use to derive a replacement value from an array element at a specific index
1949 * while leaving the other elements unchanged.
1950 *
1951 * **Details**
1952 *
1953 * Returns `Option.none()` when the index is out of bounds.
1954 *
1955 * **Example** (Modifying an element)
1956 *
1957 * ```ts import.meta.vitest
1958 * import { Array, Option } from "effect"
1959 *
1960 * const values = [1, 2, 3, 4]
1961 * const double = (n: number) => n * 2
1962 *
1963 * Array.modify(values, 2, double) // => Option.some([1, 2, 6, 4])
1964 * Array.modify(values, 5, double) // => Option.none()
1965 * ```
1966 *
1967 * @see {@link replace} — set a fixed value at an index
1968 * @see {@link modifyHeadNonEmpty} — modify the first element
1969 * @see {@link modifyLastNonEmpty} — modify the last element
1970 *
1971 * @category transforming
1972 * @since 2.0.0
1973 */
1974export const modify: {
1975 <A, B, S extends Iterable<A> = Iterable<A>>(
1976 i: number,
1977 f: (a: ReadonlyArray.Infer<S>) => B
1978 ): (self: S) => Option.Option<ReadonlyArray.With<S, ReadonlyArray.Infer<S> | B>>
1979 <A, B, S extends Iterable<A> = Iterable<A>>(
1980 self: S,
1981 i: number,
1982 f: (a: ReadonlyArray.Infer<S>) => B
1983 ): Option.Option<ReadonlyArray.With<S, ReadonlyArray.Infer<S> | B>>
1984} = dual(3, <A, B>(self: Iterable<A>, i: number, f: (a: A) => B): Option.Option<Array<A | B>> => {
1985 const arr = Array.from(self)
1986 const index = Math.floor(i)
1987 if (isOutOfBounds(index, arr)) {
1988 return Option.none()
1989 }
1990 const out: Array<A | B> = arr
1991 const b = f(arr[index])
1992 out[index] = b
1993 return Option.some(out)
1994})
1995
1996/**
1997 * Removes the element at the specified index, returning a new array. If the
1998 * index is out of bounds, returns a copy of the original.
1999 *
2000 * **When to use**
2001 *
2002 * Use when you want a missing index to be a no-op and need a fresh array result
2003 * instead of an optional failure.
2004 *
2005 * **Example** (Removing an element)
2006 *
2007 * ```ts import.meta.vitest
2008 * import { Array } from "effect"
2009 *
2010 * Array.remove([1, 2, 3, 4], 2) // => [1, 2, 4]
2011 * Array.remove([1, 2, 3, 4], 5) // => [1, 2, 3, 4]
2012 * ```
2013 *
2014 * @see {@link insertAt} — insert an element
2015 * @see {@link filter} — remove elements by predicate
2016 *
2017 * @category transforming
2018 * @since 2.0.0
2019 */
2020export const remove: {
2021 (i: number): <A>(self: Iterable<A>) => Array<A>
2022 <A>(self: Iterable<A>, i: number): Array<A>
2023} = dual(2, <A>(self: Iterable<A>, i: number): Array<A> => {
2024 const out = Array.from(self)
2025 const index = Math.floor(i)
2026 if (isOutOfBounds(index, out)) {
2027 return out
2028 }
2029 out.splice(index, 1)
2030 return out
2031})
2032
2033/**
2034 * Reverses an iterable into a new array.
2035 *
2036 * **When to use**
2037 *
2038 * Use to reverse an iterable into a new array without mutating the original
2039 * input.
2040 *
2041 * **Details**
2042 *
2043 * Preserves `NonEmptyArray` in the return type.
2044 *
2045 * **Example** (Reversing an array)
2046 *
2047 * ```ts import.meta.vitest
2048 * import { Array } from "effect"
2049 *
2050 * Array.reverse([1, 2, 3, 4]) // => [4, 3, 2, 1]
2051 * ```
2052 *
2053 * @category transforming
2054 * @since 2.0.0
2055 */
2056export const reverse = <S extends Iterable<any>>(
2057 self: S
2058): S extends NonEmptyReadonlyArray<infer A> ? NonEmptyArray<A> : S extends Iterable<infer A> ? Array<A> : never =>
2059 Array.from(self).reverse() as any
2060
2061/**
2062 * Sorts an array by the given `Order`, returning a new array.
2063 *
2064 * **When to use**
2065 *
2066 * Use to sort an array using a single `Order` comparator.
2067 *
2068 * **Details**
2069 *
2070 * Preserves `NonEmptyArray` in the return type. Use `sortWith` to sort by a
2071 * derived key, or `sortBy` for multi-key sorting.
2072 *
2073 * **Example** (Sorting numbers)
2074 *
2075 * ```ts import.meta.vitest
2076 * import { Array, Order } from "effect"
2077 *
2078 * Array.sort([3, 1, 4, 1, 5], Order.Number) // => [1, 1, 3, 4, 5]
2079 * ```
2080 *
2081 * @see {@link sortWith} — sort by a mapping function
2082 * @see {@link sortBy} — sort by multiple orders
2083 *
2084 * @category sorting
2085 * @since 2.0.0
2086 */
2087export const sort: {
2088 <B>(
2089 O: Order.Order<B>
2090 ): <A extends B, S extends Iterable<A>>(self: S) => ReadonlyArray.With<S, ReadonlyArray.Infer<S>>
2091 <A extends B, B>(self: NonEmptyReadonlyArray<A>, O: Order.Order<B>): NonEmptyArray<A>
2092 <A extends B, B>(self: Iterable<A>, O: Order.Order<B>): Array<A>
2093} = dual(2, <A extends B, B>(self: Iterable<A>, O: Order.Order<B>): Array<A> => {
2094 const out = Array.from(self)
2095 out.sort(O)
2096 return out
2097})
2098
2099/**
2100 * Sorts an array by a derived key using a mapping function and an `Order` for
2101 * that key.
2102 *
2103 * **When to use**
2104 *
2105 * Use when you need to sort values by a derived key, such as a string length or
2106 * object field, while keeping the original values.
2107 *
2108 * **Details**
2109 *
2110 * Equivalent to `sort(Order.mapInput(order, f))`, but more convenient.
2111 *
2112 * **Example** (Sorting strings by length)
2113 *
2114 * ```ts import.meta.vitest
2115 * import { Array, Order } from "effect"
2116 *
2117 * Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.Number) // => ["b", "cc", "aaa"]
2118 * ```
2119 *
2120 * @see {@link sort} for sorting with an `Order` that compares the elements directly
2121 * @see {@link sortBy} for sorting with multiple `Order`s applied in sequence
2122 *
2123 * @category sorting
2124 * @since 2.0.0
2125 */
2126export const sortWith: {
2127 <S extends Iterable<any>, B>(
2128 f: (a: ReadonlyArray.Infer<S>) => B,
2129 order: Order.Order<B>
2130 ): (self: S) => ReadonlyArray.With<S, ReadonlyArray.Infer<S>>
2131 <A, B>(self: NonEmptyReadonlyArray<A>, f: (a: A) => B, O: Order.Order<B>): NonEmptyArray<A>
2132 <A, B>(self: Iterable<A>, f: (a: A) => B, order: Order.Order<B>): Array<A>
2133} = dual(
2134 3,
2135 <A, B>(self: Iterable<A>, f: (a: A) => B, order: Order.Order<B>): Array<A> =>
2136 Array.from(self).map((a) => [a, f(a)] as const).sort(([, a], [, b]) => order(a, b)).map(([_]) => _)
2137)
2138
2139/**
2140 * Sorts an array by multiple `Order`s applied in sequence: the first order is
2141 * used first; ties are broken by the second order, and so on.
2142 *
2143 * **When to use**
2144 *
2145 * Use to sort by multiple criteria where later orders break ties from earlier
2146 * ones.
2147 *
2148 * **Details**
2149 *
2150 * This is data-last only and returns a function. The return type preserves
2151 * `NonEmptyArray`.
2152 *
2153 * **Example** (Sorting by multiple keys)
2154 *
2155 * ```ts import.meta.vitest
2156 * import { Array, Order, pipe } from "effect"
2157 *
2158 * const users = [
2159 * { name: "Alice", age: 30 },
2160 * { name: "Bob", age: 25 },
2161 * { name: "Charlie", age: 30 }
2162 * ]
2163 *
2164 * const sortedUsers = pipe(
2165 * users,
2166 * Array.sortBy(
2167 * Order.mapInput(Order.Number, (user: (typeof users)[number]) => user.age),
2168 * Order.mapInput(Order.String, (user: (typeof users)[number]) => user.name)
2169 * )
2170 * )
2171 *
2172 * sortedUsers.map((user) => user.name).join(",") // => "Bob,Alice,Charlie"
2173 * ```
2174 *
2175 * @see {@link sort} — sort by a single `Order`
2176 * @see {@link sortWith} — sort by a derived key
2177 *
2178 * @category sorting
2179 * @since 2.0.0
2180 */
2181export const sortBy = <S extends Iterable<any>>(
2182 ...orders: ReadonlyArray<Order.Order<ReadonlyArray.Infer<S>>>
2183) => {
2184 const sortByAll = sort(Order.combineAll(orders))
2185 return (
2186 self: S
2187 ): S extends NonEmptyReadonlyArray<infer A> ? NonEmptyArray<A> : S extends Iterable<infer A> ? Array<A> : never => {
2188 const input = fromIterable(self)
2189 if (isReadonlyArrayNonEmpty(input)) {
2190 return sortByAll(input) as any
2191 }
2192 return [] as any
2193 }
2194}
2195
2196/**
2197 * Pairs elements from two iterables by position. If the iterables differ in
2198 * length, the extra elements from the longer one are discarded.
2199 *
2200 * **When to use**
2201 *
2202 * Use when you need simple pairs of corresponding elements from two iterables.
2203 *
2204 * **Details**
2205 *
2206 * Returns `NonEmptyArray` when both inputs are non-empty.
2207 *
2208 * **Example** (Zipping two arrays)
2209 *
2210 * ```ts import.meta.vitest
2211 * import { Array } from "effect"
2212 *
2213 * Array.zip([1, 2, 3], ["a", "b"]) // => [[1, "a"], [2, "b"]]
2214 * ```
2215 *
2216 * @see {@link zipWith} — zip with a combiner function
2217 * @see {@link unzip} — inverse operation
2218 *
2219 * @category zipping
2220 * @since 2.0.0
2221 */
2222export const zip: {
2223 <B>(that: NonEmptyReadonlyArray<B>): <A>(self: NonEmptyReadonlyArray<A>) => NonEmptyArray<[A, B]>
2224 <B>(that: Iterable<B>): <A>(self: Iterable<A>) => Array<[A, B]>
2225 <A, B>(self: NonEmptyReadonlyArray<A>, that: NonEmptyReadonlyArray<B>): NonEmptyArray<[A, B]>
2226 <A, B>(self: Iterable<A>, that: Iterable<B>): Array<[A, B]>
2227} = dual(
2228 2,
2229 <A, B>(self: Iterable<A>, that: Iterable<B>): Array<[A, B]> => zipWith(self, that, Tuple.make)
2230)
2231
2232/**
2233 * Combines elements from two iterables pairwise using a function. If the
2234 * iterables differ in length, extra elements are discarded.
2235 *
2236 * **When to use**
2237 *
2238 * Use when zipping two iterables in an array pipeline and each pair should
2239 * become a computed array element instead of a tuple.
2240 *
2241 * **Example** (Zipping with addition)
2242 *
2243 * ```ts import.meta.vitest
2244 * import { Array } from "effect"
2245 *
2246 * Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b) // => [5, 7, 9]
2247 * ```
2248 *
2249 * @see {@link zip} — zip into tuples
2250 *
2251 * @category zipping
2252 * @since 2.0.0
2253 */
2254export const zipWith: {
2255 <B, A, C>(that: NonEmptyReadonlyArray<B>, f: (a: A, b: B) => C): (self: NonEmptyReadonlyArray<A>) => NonEmptyArray<C>
2256 <B, A, C>(that: Iterable<B>, f: (a: A, b: B) => C): (self: Iterable<A>) => Array<C>
2257 <A, B, C>(self: NonEmptyReadonlyArray<A>, that: NonEmptyReadonlyArray<B>, f: (a: A, b: B) => C): NonEmptyArray<C>
2258 <B, A, C>(self: Iterable<A>, that: Iterable<B>, f: (a: A, b: B) => C): Array<C>
2259} = dual(3, <B, A, C>(self: Iterable<A>, that: Iterable<B>, f: (a: A, b: B) => C): Array<C> => {
2260 const as = fromIterable(self)
2261 const bs = fromIterable(that)
2262 if (isReadonlyArrayNonEmpty(as) && isReadonlyArrayNonEmpty(bs)) {
2263 const out: NonEmptyArray<C> = [f(headNonEmpty(as), headNonEmpty(bs))]
2264 const len = Math.min(as.length, bs.length)
2265 for (let i = 1; i < len; i++) {
2266 out[i] = f(as[i], bs[i])
2267 }
2268 return out
2269 }
2270 return []
2271})
2272
2273/**
2274 * Splits an array of pairs into two arrays. Inverse of {@link zip}.
2275 *
2276 * **Example** (Unzipping pairs)
2277 *
2278 * ```ts import.meta.vitest
2279 * import { Array } from "effect"
2280 *
2281 * Array.unzip([[1, "a"], [2, "b"], [3, "c"]]) // => [[1, 2, 3], ["a", "b", "c"]]
2282 * ```
2283 *
2284 * @see {@link zip} — combine two arrays into pairs
2285 *
2286 * @category zipping
2287 * @since 2.0.0
2288 */
2289export const unzip: <S extends Iterable<readonly [any, any]>>(
2290 self: S
2291) => S extends NonEmptyReadonlyArray<readonly [infer A, infer B]> ? [NonEmptyArray<A>, NonEmptyArray<B>]
2292 : S extends Iterable<readonly [infer A, infer B]> ? [Array<A>, Array<B>]
2293 : never = (<A, B>(self: Iterable<readonly [A, B]>): [Array<A>, Array<B>] => {
2294 const input = fromIterable(self)
2295 if (isReadonlyArrayNonEmpty(input)) {
2296 const fa: NonEmptyArray<A> = [input[0][0]]
2297 const fb: NonEmptyArray<B> = [input[0][1]]
2298 for (let i = 1; i < input.length; i++) {
2299 fa[i] = input[i][0]
2300 fb[i] = input[i][1]
2301 }
2302 return [fa, fb]
2303 }
2304 return [[], []]
2305 }) as any
2306
2307/**
2308 * Places a separator element between every pair of elements.
2309 *
2310 * **When to use**
2311 *
2312 * Use to insert a separator between elements, for example when preparing data for display or concatenation.
2313 *
2314 * **Details**
2315 *
2316 * The return type preserves `NonEmptyArray`. Empty inputs produce an empty
2317 * result.
2318 *
2319 * **Example** (Interspersing a separator)
2320 *
2321 * ```ts import.meta.vitest
2322 * import { Array } from "effect"
2323 *
2324 * Array.intersperse([1, 2, 3], 0) // => [1, 0, 2, 0, 3]
2325 * ```
2326 *
2327 * @see {@link join} — intersperse and join into a string
2328 *
2329 * @category transforming
2330 * @since 2.0.0
2331 */
2332export const intersperse: {
2333 <B>(
2334 middle: B
2335 ): <S extends Iterable<any>>(self: S) => ReadonlyArray.With<S, ReadonlyArray.Infer<S> | B>
2336 <A, B>(self: NonEmptyReadonlyArray<A>, middle: B): NonEmptyArray<A | B>
2337 <A, B>(self: Iterable<A>, middle: B): Array<A | B>
2338} = dual(2, <A, B>(self: Iterable<A>, middle: B): Array<A | B> => {
2339 const input = fromIterable(self)
2340 if (isReadonlyArrayNonEmpty(input)) {
2341 const out: NonEmptyArray<A | B> = [headNonEmpty(input)]
2342 const tail = tailNonEmpty(input)
2343 for (let i = 0; i < tail.length; i++) {
2344 if (i < tail.length) {
2345 out.push(middle)
2346 }
2347 out.push(tail[i])
2348 }
2349 return out
2350 }
2351 return []
2352})
2353
2354/**
2355 * Applies a function to the first element of a non-empty array, returning a
2356 * new array.
2357 *
2358 * **When to use**
2359 *
2360 * Use to transform the first element of a non-empty array while preserving the rest.
2361 *
2362 * **Example** (Modifying the head)
2363 *
2364 * ```ts import.meta.vitest
2365 * import { Array } from "effect"
2366 *
2367 * Array.modifyHeadNonEmpty([1, 2, 3], (n) => n * 10) // => [10, 2, 3]
2368 * ```
2369 *
2370 * @see {@link setHeadNonEmpty} — replace with a fixed value
2371 * @see {@link modifyLastNonEmpty} — modify the last element
2372 *
2373 * @category transforming
2374 * @since 4.0.0
2375 */
2376export const modifyHeadNonEmpty: {
2377 <A, B>(f: (a: A) => B): (self: NonEmptyReadonlyArray<A>) => NonEmptyArray<A | B>
2378 <A, B>(self: NonEmptyReadonlyArray<A>, f: (a: A) => B): NonEmptyArray<A | B>
2379} = dual(
2380 2,
2381 <A, B>(
2382 self: NonEmptyReadonlyArray<A>,
2383 f: (a: A) => B
2384 ): NonEmptyArray<A | B> => [f(headNonEmpty(self)), ...tailNonEmpty(self)]
2385)
2386
2387/**
2388 * Replaces the first element of a non-empty array with a new value.
2389 *
2390 * **When to use**
2391 *
2392 * Use when you already know the array is non-empty and the replacement value
2393 * does not depend on the current first element.
2394 *
2395 * **Example** (Setting the head)
2396 *
2397 * ```ts import.meta.vitest
2398 * import { Array } from "effect"
2399 *
2400 * Array.setHeadNonEmpty([1, 2, 3], 10) // => [10, 2, 3]
2401 * ```
2402 *
2403 * @see {@link modifyHeadNonEmpty} — transform the head with a function
2404 * @see {@link setLastNonEmpty} — replace the last element
2405 *
2406 * @category transforming
2407 * @since 4.0.0
2408 */
2409export const setHeadNonEmpty: {
2410 <B>(b: B): <A>(self: NonEmptyReadonlyArray<A>) => NonEmptyArray<A | B>
2411 <A, B>(self: NonEmptyReadonlyArray<A>, b: B): NonEmptyArray<A | B>
2412} = dual(
2413 2,
2414 <A, B>(self: NonEmptyReadonlyArray<A>, b: B): NonEmptyArray<A | B> => modifyHeadNonEmpty(self, () => b)
2415)
2416
2417/**
2418 * Applies a function to the last element of a non-empty array, returning a
2419 * new array.
2420 *
2421 * **When to use**
2422 *
2423 * Use when you already know the array is non-empty and the new last element
2424 * depends on the current last element.
2425 *
2426 * **Example** (Modifying the last element)
2427 *
2428 * ```ts import.meta.vitest
2429 * import { Array } from "effect"
2430 *
2431 * Array.modifyLastNonEmpty([1, 2, 3], (n) => n * 2) // => [1, 2, 6]
2432 * ```
2433 *
2434 * @see {@link setLastNonEmpty} — replace with a fixed value
2435 * @see {@link modifyHeadNonEmpty} — modify the first element
2436 *
2437 * @category transforming
2438 * @since 4.0.0
2439 */
2440export const modifyLastNonEmpty: {
2441 <A, B>(f: (a: A) => B): (self: NonEmptyReadonlyArray<A>) => NonEmptyArray<A | B>
2442 <A, B>(self: NonEmptyReadonlyArray<A>, f: (a: A) => B): NonEmptyArray<A | B>
2443} = dual(
2444 2,
2445 <A, B>(self: NonEmptyReadonlyArray<A>, f: (a: A) => B): NonEmptyArray<A | B> =>
2446 append(initNonEmpty(self), f(lastNonEmpty(self)))
2447)
2448
2449/**
2450 * Replaces the last element of a non-empty array with a new value.
2451 *
2452 * **When to use**
2453 *
2454 * Use when you already know the array is non-empty and the replacement value
2455 * does not depend on the current last element.
2456 *
2457 * **Example** (Setting the last element)
2458 *
2459 * ```ts import.meta.vitest
2460 * import { Array } from "effect"
2461 *
2462 * Array.setLastNonEmpty([1, 2, 3], 4) // => [1, 2, 4]
2463 * ```
2464 *
2465 * @see {@link modifyLastNonEmpty} — transform the last element with a function
2466 * @see {@link setHeadNonEmpty} — replace the first element
2467 *
2468 * @category transforming
2469 * @since 4.0.0
2470 */
2471export const setLastNonEmpty: {
2472 <B>(b: B): <A>(self: NonEmptyReadonlyArray<A>) => NonEmptyArray<A | B>
2473 <A, B>(self: NonEmptyReadonlyArray<A>, b: B): NonEmptyArray<A | B>
2474} = dual(
2475 2,
2476 <A, B>(self: NonEmptyReadonlyArray<A>, b: B): NonEmptyArray<A | B> => modifyLastNonEmpty(self, () => b)
2477)
2478
2479/**
2480 * Transforms an array by rotating it `n` steps. Positive `n` rotates right; negative `n`
2481 * rotates left.
2482 *
2483 * **When to use**
2484 *
2485 * Use when elements should wrap around the end of the array rather than being
2486 * dropped.
2487 *
2488 * **Details**
2489 *
2490 * `n` is rounded to the nearest integer before rotating. The return type
2491 * preserves `NonEmptyArray`. Empty arrays, or rotations normalized to `0`,
2492 * return a copy.
2493 *
2494 * **Example** (Rotating elements)
2495 *
2496 * ```ts import.meta.vitest
2497 * import { Array } from "effect"
2498 *
2499 * Array.rotate(["a", "b", "c", "d"], 2) // => ["c", "d", "a", "b"]
2500 * ```
2501 *
2502 * @see {@link take} for taking a fixed number of elements from the start
2503 * @see {@link drop} for dropping a fixed number of elements from the start
2504 *
2505 * @category transforming
2506 * @since 2.0.0
2507 */
2508export const rotate: {
2509 (n: number): <S extends Iterable<any>>(self: S) => ReadonlyArray.With<S, ReadonlyArray.Infer<S>>
2510 <A>(self: NonEmptyReadonlyArray<A>, n: number): NonEmptyArray<A>
2511 <A>(self: Iterable<A>, n: number): Array<A>
2512} = dual(2, <A>(self: Iterable<A>, n: number): Array<A> => {
2513 const input = fromIterable(self)
2514 if (isReadonlyArrayNonEmpty(input)) {
2515 const len = input.length
2516 const m = Math.round(n) % len
2517 if (isOutOfBounds(Math.abs(m), input) || m === 0) {
2518 return copy(input)
2519 }
2520 if (m < 0) {
2521 const [f, s] = splitAtNonEmpty(input, -m)
2522 return appendAll(s, f)
2523 } else {
2524 return rotate(input, m - len)
2525 }
2526 }
2527 return []
2528})
2529
2530/**
2531 * Returns a membership-test function using a custom equivalence.
2532 *
2533 * **When to use**
2534 *
2535 * Use when checking membership with caller-provided equality instead of
2536 * `Equal.equivalence()`.
2537 *
2538 * **Example** (Checking with custom equality)
2539 *
2540 * ```ts import.meta.vitest
2541 * import { Array, pipe } from "effect"
2542 *
2543 * const containsNumber = Array.containsWith((a: number, b: number) => a === b)
2544 *
2545 * pipe([1, 2, 3, 4], containsNumber(3)) // => true
2546 * ```
2547 *
2548 * @see {@link contains} for the `Equal.equivalence()` variant
2549 *
2550 * @category predicates
2551 * @since 2.0.0
2552 */
2553export const containsWith = <A>(isEquivalent: (self: A, that: A) => boolean): {
2554 (a: A): (self: Iterable<A>) => boolean
2555 (self: Iterable<A>, a: A): boolean
2556} =>
2557 dual(2, (self: Iterable<A>, a: A): boolean => {
2558 for (const i of self) {
2559 if (isEquivalent(a, i)) {
2560 return true
2561 }
2562 }
2563 return false
2564 })
2565
2566/**
2567 * Checks whether an array contains a value, using `Equal.equivalence()` for
2568 * comparison.
2569 *
2570 * **When to use**
2571 *
2572 * Use to check whether an iterable contains a value using Effect's default
2573 * equality instead of providing a comparison function.
2574 *
2575 * **Example** (Checking membership)
2576 *
2577 * ```ts import.meta.vitest
2578 * import { Array, pipe } from "effect"
2579 *
2580 * pipe(["a", "b", "c", "d"], Array.contains("c")) // => true
2581 * ```
2582 *
2583 * @see {@link containsWith} — use custom equality
2584 *
2585 * @category predicates
2586 * @since 2.0.0
2587 */
2588export const contains: {
2589 <A>(a: A): (self: Iterable<A>) => boolean
2590 <A>(self: Iterable<A>, a: A): boolean
2591} = containsWith(Equal.asEquivalence())
2592
2593/**
2594 * Applies a function repeatedly to consume prefixes of the array and collect
2595 * the values it produces.
2596 *
2597 * **When to use**
2598 *
2599 * Use when you need custom grouping logic where each step returns both a value
2600 * and the remaining input.
2601 *
2602 * **Details**
2603 *
2604 * The function receives a `NonEmptyReadonlyArray` and returns `[value, rest]`.
2605 * Processing continues until the remaining array is empty.
2606 *
2607 * **Example** (Chopping an array)
2608 *
2609 * ```ts import.meta.vitest
2610 * import { Array } from "effect"
2611 *
2612 * Array.chop([1, 2, 3, 4, 5], (as): [number, Array<number>] => [as[0] * 2, as.slice(1)]) // => [2, 4, 6, 8, 10]
2613 * ```
2614 *
2615 * @see {@link chunksOf} — split into fixed-size chunks
2616 * @see {@link splitAt} — split at an index
2617 *
2618 * @category splitting
2619 * @since 2.0.0
2620 */
2621export const chop: {
2622 <S extends Iterable<any>, B>(
2623 f: (as: NonEmptyReadonlyArray<ReadonlyArray.Infer<S>>) => readonly [B, ReadonlyArray<ReadonlyArray.Infer<S>>]
2624 ): (self: S) => ReadonlyArray.With<S, ReadonlyArray.Infer<S>>
2625 <A, B>(
2626 self: NonEmptyReadonlyArray<A>,
2627 f: (as: NonEmptyReadonlyArray<A>) => readonly [B, ReadonlyArray<A>]
2628 ): NonEmptyArray<B>
2629 <A, B>(
2630 self: Iterable<A>,
2631 f: (as: NonEmptyReadonlyArray<A>) => readonly [B, ReadonlyArray<A>]
2632 ): Array<B>
2633} = dual(2, <A, B>(
2634 self: Iterable<A>,
2635 f: (as: NonEmptyReadonlyArray<A>) => readonly [B, ReadonlyArray<A>]
2636): Array<B> => {
2637 const input = fromIterable(self)
2638 if (isReadonlyArrayNonEmpty(input)) {
2639 const [b, rest] = f(input)
2640 const out: NonEmptyArray<B> = [b]
2641 let next: ReadonlyArray<A> = rest
2642 while (internalArray.isArrayNonEmpty(next)) {
2643 const [b, rest] = f(next)
2644 out.push(b)
2645 next = rest
2646 }
2647 return out
2648 }
2649 return []
2650})
2651
2652/**
2653 * Splits an iterable into two arrays at the given index.
2654 *
2655 * **When to use**
2656 *
2657 * Use to divide an array into a prefix and suffix at a specific position.
2658 *
2659 * **Details**
2660 *
2661 * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`,
2662 * which places all elements in the second array.
2663 *
2664 * **Example** (Splitting at an index)
2665 *
2666 * ```ts import.meta.vitest
2667 * import { Array } from "effect"
2668 *
2669 * Array.splitAt([1, 2, 3, 4, 5], 3) // => [[1, 2, 3], [4, 5]]
2670 * ```
2671 *
2672 * @see {@link splitAtNonEmpty} — for non-empty arrays
2673 * @see {@link splitWhere} — split at a predicate boundary
2674 *
2675 * @category splitting
2676 * @since 2.0.0
2677 */
2678export const splitAt: {
2679 (n: number): <A>(self: Iterable<A>) => [beforeIndex: Array<A>, fromIndex: Array<A>]
2680 <A>(self: Iterable<A>, n: number): [beforeIndex: Array<A>, fromIndex: Array<A>]
2681} = dual(2, <A>(self: Iterable<A>, n: number): [Array<A>, Array<A>] => {
2682 const input = Array.from(self)
2683 const _n = Count.normalize(n)
2684 if (isReadonlyArrayNonEmpty(input)) {
2685 if (_n >= 1) {
2686 return splitAtNonEmpty(input, _n)
2687 }
2688 return [[], input]
2689 }
2690 return [input, []]
2691})
2692
2693/**
2694 * Splits a non-empty array into two parts at the given index. The first part
2695 * is guaranteed to be non-empty (`n` is clamped to >= 1).
2696 *
2697 * **When to use**
2698 *
2699 * Use when downstream code requires the left side of the split to contain at
2700 * least one element.
2701 *
2702 * **Details**
2703 *
2704 * `n` is rounded down and clamped to `[1, length]`. `NaN` is treated as `1`.
2705 *
2706 * **Example** (Splitting a non-empty array)
2707 *
2708 * ```ts import.meta.vitest
2709 * import { Array } from "effect"
2710 *
2711 * Array.splitAtNonEmpty(["a", "b", "c", "d", "e"], 3) // => [["a", "b", "c"], ["d", "e"]]
2712 * ```
2713 *
2714 * @see {@link splitAt} — for possibly-empty arrays
2715 *
2716 * @category splitting
2717 * @since 4.0.0
2718 */
2719export const splitAtNonEmpty: {
2720 (n: number): <A>(self: NonEmptyReadonlyArray<A>) => [beforeIndex: NonEmptyArray<A>, fromIndex: Array<A>]
2721 <A>(self: NonEmptyReadonlyArray<A>, n: number): [beforeIndex: NonEmptyArray<A>, fromIndex: Array<A>]
2722} = dual(2, <A>(self: NonEmptyReadonlyArray<A>, n: number): [NonEmptyArray<A>, Array<A>] => {
2723 const _n = Count.normalizeNonEmpty(n)
2724 return _n >= self.length ?
2725 [copy(self), []] :
2726 [prepend(self.slice(1, _n), headNonEmpty(self)), self.slice(_n)]
2727})
2728
2729/**
2730 * Splits an iterable into `n` roughly equal-sized chunks.
2731 *
2732 * **When to use**
2733 *
2734 * Use to distribute elements across a fixed number of groups, such as when splitting work across threads.
2735 *
2736 * **Details**
2737 *
2738 * `n` is rounded down and normalized to at least `1`, with `NaN` treated as
2739 * `1`. The last chunk may be shorter.
2740 *
2741 * **Example** (Splitting into groups)
2742 *
2743 * ```ts import.meta.vitest
2744 * import { Array } from "effect"
2745 *
2746 * Array.split([1, 2, 3, 4, 5, 6, 7, 8], 3) // => [[1, 2, 3], [4, 5, 6], [7, 8]]
2747 * ```
2748 *
2749 * @see {@link chunksOf} — split into fixed-size chunks
2750 *
2751 * @category splitting
2752 * @since 2.0.0
2753 */
2754export const split: {
2755 (n: number): <A>(self: Iterable<A>) => Array<Array<A>>
2756 <A>(self: Iterable<A>, n: number): Array<Array<A>>
2757} = dual(2, <A>(self: Iterable<A>, n: number) => {
2758 const input = fromIterable(self)
2759 return chunksOf(input, Math.ceil(input.length / Count.normalizeNonEmpty(n)))
2760})
2761
2762/**
2763 * Splits an iterable at the first element matching the predicate. The matching
2764 * element is included in the second array.
2765 *
2766 * **When to use**
2767 *
2768 * Use when you need to split an array at the first element that marks a
2769 * condition boundary.
2770 *
2771 * **Example** (Splitting at a condition)
2772 *
2773 * ```ts import.meta.vitest
2774 * import { Array } from "effect"
2775 *
2776 * Array.splitWhere([1, 2, 3, 4, 5], (n) => n > 3) // => [[1, 2, 3], [4, 5]]
2777 * ```
2778 *
2779 * @see {@link span} — splits at the first element that fails the predicate
2780 * @see {@link splitAt} — split at a fixed index
2781 *
2782 * @category splitting
2783 * @since 2.0.0
2784 */
2785export const splitWhere: {
2786 <A>(
2787 predicate: (a: NoInfer<A>, i: number) => boolean
2788 ): (self: Iterable<A>) => [beforeMatch: Array<A>, fromMatch: Array<A>]
2789 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): [beforeMatch: Array<A>, fromMatch: Array<A>]
2790} = dual(
2791 2,
2792 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): [beforeMatch: Array<A>, fromMatch: Array<A>] =>
2793 span(self, (a: A, i: number) => !predicate(a, i))
2794)
2795
2796/**
2797 * Creates a shallow copy of an array.
2798 *
2799 * **When to use**
2800 *
2801 * Use to create a distinct array reference for an existing array, for example
2802 * before mutating the returned array.
2803 *
2804 * **Details**
2805 *
2806 * The return type preserves `NonEmptyArray`. Use this when you need a distinct
2807 * reference, for example before mutating the returned array.
2808 *
2809 * **Example** (Copying an array)
2810 *
2811 * ```ts import.meta.vitest
2812 * import { Array } from "effect"
2813 *
2814 * const original = [1, 2, 3]
2815 * const copied = Array.copy(original)
2816 *
2817 * copied // => [1, 2, 3]
2818 * original === copied // => false
2819 * ```
2820 *
2821 * @see {@link fromIterable} — returns the same reference for arrays
2822 *
2823 * @category transforming
2824 * @since 2.0.0
2825 */
2826export const copy: {
2827 <A>(self: NonEmptyReadonlyArray<A>): NonEmptyArray<A>
2828 <A>(self: ReadonlyArray<A>): Array<A>
2829} = (<A>(self: ReadonlyArray<A>): Array<A> => self.slice()) as any
2830
2831/**
2832 * Pads or truncates an array to exactly `n` elements, filling with `fill`
2833 * if the array is shorter, or slicing if longer.
2834 *
2835 * **When to use**
2836 *
2837 * Use to ensure an array has a specific length, padding with a fill value or truncating as needed.
2838 *
2839 * **Details**
2840 *
2841 * `n` is rounded down. `NaN` and non-positive values are treated as `0`, which
2842 * returns an empty array.
2843 *
2844 * **Example** (Padding an array)
2845 *
2846 * ```ts import.meta.vitest
2847 * import { Array } from "effect"
2848 *
2849 * Array.pad([1, 2, 3], 6, 0) // => [1, 2, 3, 0, 0, 0]
2850 * ```
2851 *
2852 * @see {@link take} — truncate without padding
2853 * @see {@link replicate} — create an array of a single repeated value
2854 *
2855 * @category transforming
2856 * @since 3.8.4
2857 */
2858export const pad: {
2859 <A, T>(
2860 n: number,
2861 fill: T
2862 ): (
2863 self: Array<A>
2864 ) => Array<A | T>
2865 <A, T>(self: Array<A>, n: number, fill: T): Array<A | T>
2866} = dual(3, <A, T>(self: Array<A>, n: number, fill: T): Array<A | T> => {
2867 const length = Count.normalize(n)
2868 if (self.length >= length) {
2869 return take(self, length)
2870 }
2871 return appendAll(
2872 self,
2873 makeBy(length - self.length, () => fill)
2874 )
2875})
2876
2877/**
2878 * Splits an iterable into chunks of length `n`. The last chunk may be shorter
2879 * if `n` does not evenly divide the length.
2880 *
2881 * **When to use**
2882 *
2883 * Use to divide an iterable into a new array of non-overlapping chunks with a
2884 * maximum chunk size.
2885 *
2886 * **Details**
2887 *
2888 * `n` is rounded down and normalized to at least `1`; `NaN` and non-positive
2889 * values therefore produce singleton chunks. `chunksOf(n)([])` is `[]`, not
2890 * `[[]]`. Each chunk is a `NonEmptyArray`, and the outer return type preserves
2891 * `NonEmptyArray`.
2892 *
2893 * **Example** (Chunking an array)
2894 *
2895 * ```ts import.meta.vitest
2896 * import { Array } from "effect"
2897 *
2898 * Array.chunksOf([1, 2, 3, 4, 5], 2) // => [[1, 2], [3, 4], [5]]
2899 * ```
2900 *
2901 * @see {@link split} — split into a given number of groups
2902 * @see {@link window} — sliding windows
2903 *
2904 * @category splitting
2905 * @since 2.0.0
2906 */
2907export const chunksOf: {
2908 (
2909 n: number
2910 ): <S extends Iterable<any>>(
2911 self: S
2912 ) => ReadonlyArray.With<S, NonEmptyArray<ReadonlyArray.Infer<S>>>
2913 <A>(self: NonEmptyReadonlyArray<A>, n: number): NonEmptyArray<NonEmptyArray<A>>
2914 <A>(self: Iterable<A>, n: number): Array<NonEmptyArray<A>>
2915} = dual(2, <A>(self: Iterable<A>, n: number): Array<NonEmptyArray<A>> => {
2916 const input = fromIterable(self)
2917 if (isReadonlyArrayNonEmpty(input)) {
2918 return chop(input, splitAtNonEmpty(n))
2919 }
2920 return []
2921})
2922
2923/**
2924 * Creates overlapping sliding windows of size `n`.
2925 *
2926 * **When to use**
2927 *
2928 * Use to process sequences with a moving window, such as for computing running averages or detecting patterns.
2929 *
2930 * **Details**
2931 *
2932 * `n` is rounded down, with `NaN` and non-positive values treated as `0`.
2933 * Returns an empty array if the normalized size is `0` or exceeds the array
2934 * length. Each window is a tuple of exactly the normalized size.
2935 *
2936 * **Example** (Creating sliding windows)
2937 *
2938 * ```ts import.meta.vitest
2939 * import { Array } from "effect"
2940 *
2941 * const values = [1, 2, 3, 4, 5]
2942 *
2943 * Array.window(values, 3) // => [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
2944 * Array.window(values, 6) // => []
2945 * ```
2946 *
2947 * @see {@link chunksOf} — non-overlapping chunks
2948 *
2949 * @category splitting
2950 * @since 3.13.2
2951 */
2952export const window: {
2953 <N extends number>(n: N): <A>(self: Iterable<A>) => Array<TupleOf<N, A>>
2954 <A, N extends number>(self: Iterable<A>, n: N): Array<TupleOf<N, A>>
2955} = dual(2, <A>(self: Iterable<A>, n: number): Array<Array<A>> => {
2956 const input = fromIterable(self)
2957 const size = Count.normalize(n)
2958 if (size > 0 && size <= input.length && isReadonlyArrayNonEmpty(input)) {
2959 return Array.from(
2960 { length: input.length - (size - 1) },
2961 (_, index) => input.slice(index, index + size)
2962 )
2963 }
2964 return []
2965})
2966
2967/**
2968 * Groups consecutive equal elements using a custom equivalence function.
2969 *
2970 * **When to use**
2971 *
2972 * Use when you already have a non-empty array arranged so matching elements are
2973 * adjacent and need a custom equivalence function.
2974 *
2975 * **Details**
2976 *
2977 * Only adjacent elements are grouped. Non-adjacent duplicates stay separate.
2978 * Requires a `NonEmptyReadonlyArray`.
2979 *
2980 * **Example** (Grouping consecutive equal elements)
2981 *
2982 * ```ts import.meta.vitest
2983 * import { Array } from "effect"
2984 *
2985 * Array.groupWith(
2986 * ["a", "a", "b", "b", "b", "c", "a"],
2987 * (x, y) => x === y
2988 * ) // => [["a", "a"], ["b", "b", "b"], ["c"], ["a"]]
2989 * ```
2990 *
2991 * @see {@link group} for grouping adjacent elements with `Equal.equivalence()`
2992 * @see {@link groupBy} for grouping all elements into a record by key, regardless of adjacency
2993 *
2994 * @category grouping
2995 * @since 2.0.0
2996 */
2997export const groupWith: {
2998 <A>(isEquivalent: (self: A, that: A) => boolean): (self: NonEmptyReadonlyArray<A>) => NonEmptyArray<NonEmptyArray<A>>
2999 <A>(self: NonEmptyReadonlyArray<A>, isEquivalent: (self: A, that: A) => boolean): NonEmptyArray<NonEmptyArray<A>>
3000} = dual(
3001 2,
3002 <A>(self: NonEmptyReadonlyArray<A>, isEquivalent: (self: A, that: A) => boolean): NonEmptyArray<NonEmptyArray<A>> =>
3003 chop(self, (as) => {
3004 const h = headNonEmpty(as)
3005 const out: NonEmptyArray<A> = [h]
3006 let i = 1
3007 for (; i < as.length; i++) {
3008 const a = as[i]
3009 if (isEquivalent(a, h)) {
3010 out.push(a)
3011 } else {
3012 break
3013 }
3014 }
3015 return [out, as.slice(i)]
3016 })
3017)
3018
3019/**
3020 * Groups consecutive equal elements using `Equal.equivalence()`.
3021 *
3022 * **When to use**
3023 *
3024 * Use when you already have adjacent equal values and Effect's default equality
3025 * is the right comparison.
3026 *
3027 * **Details**
3028 *
3029 * Only adjacent elements are grouped.
3030 *
3031 * **Example** (Grouping adjacent equal elements)
3032 *
3033 * ```ts import.meta.vitest
3034 * import { Array } from "effect"
3035 *
3036 * Array.group([1, 1, 2, 2, 2, 3, 1]) // => [[1, 1], [2, 2, 2], [3], [1]]
3037 * ```
3038 *
3039 * @see {@link groupWith} — use custom equality
3040 * @see {@link groupBy} — group by a key function into a record
3041 *
3042 * @category grouping
3043 * @since 2.0.0
3044 */
3045export const group: <A>(self: NonEmptyReadonlyArray<A>) => NonEmptyArray<NonEmptyArray<A>> = groupWith(
3046 Equal.asEquivalence()
3047)
3048
3049/**
3050 * Groups elements into a record by a key-returning function. Each key maps
3051 * to a `NonEmptyArray` of elements that produced that key.
3052 *
3053 * **When to use**
3054 *
3055 * Use to build buckets of elements indexed by a computed string or symbol key.
3056 *
3057 * **Details**
3058 *
3059 * Unlike `group` and `groupWith`, elements do not need to be adjacent to be
3060 * grouped together. The key function must return a `string` or `symbol`.
3061 *
3062 * **Gotchas**
3063 *
3064 * When the key function returns a finite union of string literals or unique
3065 * symbols, the result preserves those keys as optional properties because the
3066 * input may not produce every key. Open `string` and `symbol` key types retain
3067 * their record index signatures.
3068 *
3069 * **Example** (Grouping by a property)
3070 *
3071 * ```ts import.meta.vitest
3072 * import { Array } from "effect"
3073 *
3074 * const people = [
3075 * { name: "Alice", group: "A" },
3076 * { name: "Bob", group: "B" },
3077 * { name: "Charlie", group: "A" }
3078 * ]
3079 *
3080 * Object.keys(Array.groupBy(people, (person) => person.group)).join(",") // => "A,B"
3081 * ```
3082 *
3083 * @see {@link group} — group adjacent equal elements
3084 * @see {@link groupWith} — group adjacent elements by custom equality
3085 *
3086 * @category grouping
3087 * @since 2.0.0
3088 */
3089export const groupBy: {
3090 <A, K extends string | symbol>(
3091 f: (a: A) => K
3092 ): (self: Iterable<A>) => Record.ReadonlyRecord.GroupByResult<K, NonEmptyArray<A>>
3093 <A, K extends string | symbol>(
3094 self: Iterable<A>,
3095 f: (a: A) => K
3096 ): Record.ReadonlyRecord.GroupByResult<K, NonEmptyArray<A>>
3097} = dual(2, <A, K extends string | symbol>(
3098 self: Iterable<A>,
3099 f: (a: A) => K
3100): Record.ReadonlyRecord.GroupByResult<K, NonEmptyArray<A>> => {
3101 const out: Record<string | symbol, NonEmptyArray<A>> = {}
3102 for (const a of self) {
3103 const k = f(a)
3104 if (Object.hasOwn(out, k)) {
3105 out[k].push(a)
3106 } else {
3107 InternalRecord.assignProperty(out, k, [a])
3108 }
3109 }
3110 return out
3111})
3112
3113type HashBuckets = Map<number, Array<unknown>>
3114
3115const hashBucketsAdd = (buckets: HashBuckets, value: unknown): boolean => {
3116 const hash = Hash.hash(value)
3117 const bucket = buckets.get(hash)
3118 if (bucket === undefined) {
3119 buckets.set(hash, [value])
3120 return true
3121 }
3122 // Hash collisions still require an Effect equality check.
3123 for (const previous of bucket) {
3124 if (Equal.equals(previous, value)) {
3125 return false
3126 }
3127 }
3128 bucket.push(value)
3129 return true
3130}
3131
3132const makeHashBuckets = (values: Iterable<unknown>): HashBuckets => {
3133 const buckets: HashBuckets = new Map()
3134 for (const value of values) {
3135 hashBucketsAdd(buckets, value)
3136 }
3137 return buckets
3138}
3139
3140const hashBucketsHas = (buckets: HashBuckets, value: unknown): boolean => {
3141 const bucket = buckets.get(Hash.hash(value))
3142 if (bucket === undefined) {
3143 return false
3144 }
3145 for (const candidate of bucket) {
3146 if (Equal.equals(candidate, value)) {
3147 return true
3148 }
3149 }
3150 return false
3151}
3152
3153/**
3154 * Computes the union of two arrays using a custom equivalence, removing
3155 * duplicates.
3156 *
3157 * **When to use**
3158 *
3159 * Use when you need the union of two arrays but duplicate detection must use a
3160 * custom equivalence instead of the default `Equal.equivalence()`.
3161 *
3162 * **Example** (Computing unions with custom equality)
3163 *
3164 * ```ts import.meta.vitest
3165 * import { Array } from "effect"
3166 *
3167 * Array.unionWith([1, 2], [2, 3], (a, b) => a === b) // => [1, 2, 3]
3168 * ```
3169 *
3170 * @see {@link union} for the `Equal.equivalence()` variant
3171 * @see {@link intersectionWith} for keeping elements present in both arrays
3172 * @see {@link differenceWith} for keeping elements present only in the first array
3173 *
3174 * @category set operations
3175 * @since 2.0.0
3176 */
3177export const unionWith: {
3178 <S extends Iterable<any>, T extends Iterable<any>>(
3179 that: T,
3180 isEquivalent: (self: ReadonlyArray.Infer<S>, that: ReadonlyArray.Infer<T>) => boolean
3181 ): (self: S) => ReadonlyArray.OrNonEmpty<S, T, ReadonlyArray.Infer<S> | ReadonlyArray.Infer<T>>
3182 <A, B>(
3183 self: NonEmptyReadonlyArray<A>,
3184 that: Iterable<B>,
3185 isEquivalent: (self: A, that: B) => boolean
3186 ): NonEmptyArray<A | B>
3187 <A, B>(
3188 self: Iterable<A>,
3189 that: NonEmptyReadonlyArray<B>,
3190 isEquivalent: (self: A, that: B) => boolean
3191 ): NonEmptyArray<A | B>
3192 <A, B>(self: Iterable<A>, that: Iterable<B>, isEquivalent: (self: A, that: B) => boolean): Array<A | B>
3193} = dual(3, <A>(self: Iterable<A>, that: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Array<A> => {
3194 const a = fromIterable(self)
3195 const b = fromIterable(that)
3196 if (isReadonlyArrayNonEmpty(a)) {
3197 if (isReadonlyArrayNonEmpty(b)) {
3198 const dedupe = dedupeWith(isEquivalent)
3199 return dedupe(appendAll(a, b))
3200 }
3201 return a
3202 }
3203 return b
3204})
3205
3206/**
3207 * Computes the union of two arrays, removing duplicates using
3208 * `Equal.equivalence()`.
3209 *
3210 * **Example** (Computing array unions)
3211 *
3212 * ```ts import.meta.vitest
3213 * import { Array } from "effect"
3214 *
3215 * Array.union([1, 2], [2, 3]) // => [1, 2, 3]
3216 * ```
3217 *
3218 * @see {@link unionWith} — use custom equality
3219 * @see {@link intersection} — elements in both arrays
3220 * @see {@link difference} — elements only in the first array
3221 *
3222 * @category set operations
3223 * @since 2.0.0
3224 */
3225export const union: {
3226 <T extends Iterable<any>>(
3227 that: T
3228 ): <S extends Iterable<any>>(
3229 self: S
3230 ) => ReadonlyArray.OrNonEmpty<S, T, ReadonlyArray.Infer<S> | ReadonlyArray.Infer<T>>
3231 <A, B>(self: NonEmptyReadonlyArray<A>, that: ReadonlyArray<B>): NonEmptyArray<A | B>
3232 <A, B>(self: ReadonlyArray<A>, that: NonEmptyReadonlyArray<B>): NonEmptyArray<A | B>
3233 <A, B>(self: Iterable<A>, that: Iterable<B>): Array<A | B>
3234} = dual(
3235 2,
3236 <A, B>(self: Iterable<A>, that: Iterable<B>): Array<A | B> => {
3237 const a = fromIterable(self)
3238 const b = fromIterable(that)
3239 if (isReadonlyArrayNonEmpty(a)) {
3240 return isReadonlyArrayNonEmpty(b) ? dedupe(appendAll(a, b)) : a
3241 }
3242 return b
3243 }
3244)
3245
3246/**
3247 * Computes the intersection of two arrays using a custom equivalence. Order is
3248 * determined by the first array.
3249 *
3250 * **When to use**
3251 *
3252 * Use when you need to keep only values present in both arrays and equality
3253 * must be defined by a custom comparator, such as matching objects by id.
3254 *
3255 * **Example** (Computing intersections with custom equality)
3256 *
3257 * ```ts import.meta.vitest
3258 * import { Array } from "effect"
3259 *
3260 * const array1 = [{ id: 1 }, { id: 2 }, { id: 3 }]
3261 * const array2 = [{ id: 3 }, { id: 4 }, { id: 1 }]
3262 * const isEquivalent = (a: { id: number }, b: { id: number }) => a.id === b.id
3263 *
3264 * Array.intersectionWith(isEquivalent)(array2)(array1) // => [{ id: 1 }, { id: 3 }]
3265 * ```
3266 *
3267 * @see {@link intersection} for the `Equal.equivalence()` variant
3268 * @see {@link unionWith} for keeping values from either array with custom equality
3269 * @see {@link differenceWith} for keeping values only from the first array with custom equality
3270 *
3271 * @category set operations
3272 * @since 2.0.0
3273 */
3274export const intersectionWith = <A>(isEquivalent: (self: A, that: A) => boolean): {
3275 (that: Iterable<A>): (self: Iterable<A>) => Array<A>
3276 (self: Iterable<A>, that: Iterable<A>): Array<A>
3277} => {
3278 const has = containsWith(isEquivalent)
3279 return dual(
3280 2,
3281 (self: Iterable<A>, that: Iterable<A>): Array<A> => {
3282 const thatArray = fromIterable(that)
3283 return fromIterable(self).filter((a) => has(thatArray, a))
3284 }
3285 )
3286}
3287
3288/**
3289 * Computes the intersection of two arrays using `Equal.equivalence()`. Order is
3290 * determined by the first array.
3291 *
3292 * **When to use**
3293 *
3294 * Use when Effect equality is the right membership test and you want to keep
3295 * values present in both inputs while preserving the first input's order.
3296 *
3297 * **Example** (Computing array intersections)
3298 *
3299 * ```ts import.meta.vitest
3300 * import { Array } from "effect"
3301 *
3302 * Array.intersection([1, 2, 3], [3, 4, 1]) // => [1, 3]
3303 * ```
3304 *
3305 * @see {@link intersectionWith} — use custom equality
3306 * @see {@link union} — elements in either array
3307 * @see {@link difference} — elements only in the first array
3308 *
3309 * @category set operations
3310 * @since 2.0.0
3311 */
3312export const intersection: {
3313 <B>(that: Iterable<B>): <A>(self: Iterable<A>) => Array<A & B>
3314 <A, B>(self: Iterable<A>, that: Iterable<B>): Array<A & B>
3315} = dual(2, <A, B>(self: Iterable<A>, that: Iterable<B>): Array<A & B> => {
3316 const thatArray = fromIterable(that)
3317 const selfArray = fromIterable(self)
3318 if (selfArray.length === 0 || thatArray.length === 0) {
3319 return []
3320 }
3321 const buckets = makeHashBuckets(thatArray)
3322 return selfArray.filter((value): value is A & B => hashBucketsHas(buckets, value))
3323})
3324
3325/**
3326 * Computes elements in the first array that are not in the second, using a
3327 * custom equivalence.
3328 *
3329 * **When to use**
3330 *
3331 * Use when you need to keep only values from the first array and equality must
3332 * be defined by a custom comparator, such as matching objects by id.
3333 *
3334 * **Example** (Computing differences with custom equality)
3335 *
3336 * ```ts import.meta.vitest
3337 * import { Array } from "effect"
3338 *
3339 * Array.differenceWith<number>((a, b) => a === b)([1, 2, 3], [2, 3, 4]) // => [1]
3340 * ```
3341 *
3342 * @see {@link difference} for the `Equal.equivalence()` variant
3343 * @see {@link unionWith} for keeping values from either array with custom equality
3344 * @see {@link intersectionWith} for keeping values present in both arrays with custom equality
3345 *
3346 * @category set operations
3347 * @since 2.0.0
3348 */
3349export const differenceWith = <A>(isEquivalent: (self: A, that: A) => boolean): {
3350 (that: Iterable<A>): (self: Iterable<A>) => Array<A>
3351 (self: Iterable<A>, that: Iterable<A>): Array<A>
3352} => {
3353 const has = containsWith(isEquivalent)
3354 return dual(
3355 2,
3356 (self: Iterable<A>, that: Iterable<A>): Array<A> => {
3357 const thatArray = fromIterable(that)
3358 return fromIterable(self).filter((a) => !has(thatArray, a))
3359 }
3360 )
3361}
3362
3363/**
3364 * Computes elements in the first array that are not in the second, using
3365 * `Equal.equivalence()`.
3366 *
3367 * **When to use**
3368 *
3369 * Use when you need to keep values from the first array that are absent from
3370 * the second and the default `Equal.equivalence()` comparison is appropriate.
3371 *
3372 * **Example** (Computing array differences)
3373 *
3374 * ```ts import.meta.vitest
3375 * import { Array } from "effect"
3376 *
3377 * Array.difference([1, 2, 3], [2, 3, 4]) // => [1]
3378 * ```
3379 *
3380 * @see {@link differenceWith} — use custom equality
3381 * @see {@link union} — elements in either array
3382 * @see {@link intersection} — elements in both arrays
3383 *
3384 * @category set operations
3385 * @since 2.0.0
3386 */
3387export const difference: {
3388 <A>(that: Iterable<A>): (self: Iterable<A>) => Array<A>
3389 <A>(self: Iterable<A>, that: Iterable<A>): Array<A>
3390} = dual(2, <A>(self: Iterable<A>, that: Iterable<A>): Array<A> => {
3391 const thatArray = fromIterable(that)
3392 const selfArray = fromIterable(self)
3393 if (selfArray.length === 0) {
3394 return []
3395 }
3396 if (thatArray.length === 0) {
3397 return selfArray.filter(() => true)
3398 }
3399 const buckets = makeHashBuckets(thatArray)
3400 return selfArray.filter((value) => !hashBucketsHas(buckets, value))
3401})
3402
3403/**
3404 * Creates an empty array.
3405 *
3406 * **When to use**
3407 *
3408 * Use to create a typed empty array without allocating placeholder elements.
3409 *
3410 * **Example** (Creating an empty array)
3411 *
3412 * ```ts import.meta.vitest
3413 * import { Array } from "effect"
3414 *
3415 * Array.empty<number>() // => []
3416 * ```
3417 *
3418 * @see {@link of} — create a single-element array
3419 * @see {@link make} — create from multiple values
3420 *
3421 * @category constructors
3422 * @since 2.0.0
3423 */
3424export const empty: <A = never>() => Array<A> = () => []
3425
3426/**
3427 * Wraps a single value in a `NonEmptyArray`.
3428 *
3429 * **Example** (Creating a single-element array)
3430 *
3431 * ```ts import.meta.vitest
3432 * import { Array } from "effect"
3433 *
3434 * Array.of(1) // => [1]
3435 * ```
3436 *
3437 * @see {@link make} — create from multiple values
3438 * @see {@link empty} — create an empty array
3439 *
3440 * @category constructors
3441 * @since 2.0.0
3442 */
3443export const of = <A>(a: A): NonEmptyArray<A> => [a]
3444
3445/**
3446 * Utility types for working with `ReadonlyArray` at the type level. Use these
3447 * to infer element types, preserve non-emptiness, and flatten nested arrays.
3448 *
3449 * @since 2.0.0
3450 */
3451export declare namespace ReadonlyArray {
3452 /**
3453 * Infers the element type of an iterable.
3454 *
3455 * **Example** (Inferring an element type)
3456 *
3457 * ```ts import.meta.vitest
3458 * import type { Array } from "effect"
3459 *
3460 * type StringArrayType = Array.ReadonlyArray.Infer<ReadonlyArray<string>>
3461 * // StringArrayType is string
3462 * ```
3463 *
3464 * @category utility types
3465 * @since 2.0.0
3466 */
3467 export type Infer<S extends Iterable<any>> = S extends ReadonlyArray<infer A> ? A
3468 : S extends Iterable<infer A> ? A
3469 : never
3470
3471 /**
3472 * Constructs an array type preserving non-emptiness.
3473 *
3474 * **Example** (Preserving non-emptiness)
3475 *
3476 * ```ts import.meta.vitest
3477 * import type { Array } from "effect"
3478 *
3479 * type Result = Array.ReadonlyArray.With<readonly [number], string>
3480 * // Result is NonEmptyArray<string>
3481 * ```
3482 *
3483 * @category utility types
3484 * @since 2.0.0
3485 */
3486 export type With<S extends Iterable<any>, A> = S extends NonEmptyReadonlyArray<any> ? NonEmptyArray<A>
3487 : Array<A>
3488
3489 /**
3490 * Creates a non-empty array if either input is non-empty.
3491 *
3492 * **Example** (Preserving non-emptiness from either input)
3493 *
3494 * ```ts import.meta.vitest
3495 * import type { Array } from "effect"
3496 *
3497 * type Result = Array.ReadonlyArray.OrNonEmpty<
3498 * readonly [number],
3499 * ReadonlyArray<string>,
3500 * number
3501 * >
3502 * // Result is NonEmptyArray<number>
3503 * ```
3504 *
3505 * @category utility types
3506 * @since 2.0.0
3507 */
3508 export type OrNonEmpty<
3509 S extends Iterable<any>,
3510 T extends Iterable<any>,
3511 A
3512 > = S extends NonEmptyReadonlyArray<any> ? NonEmptyArray<A>
3513 : T extends NonEmptyReadonlyArray<any> ? NonEmptyArray<A>
3514 : Array<A>
3515
3516 /**
3517 * Creates a non-empty array only if both inputs are non-empty.
3518 *
3519 * **Example** (Preserving non-emptiness from both inputs)
3520 *
3521 * ```ts import.meta.vitest
3522 * import type { Array } from "effect"
3523 *
3524 * type Result = Array.ReadonlyArray.AndNonEmpty<
3525 * readonly [number],
3526 * readonly [string],
3527 * boolean
3528 * >
3529 * // Result is NonEmptyArray<boolean>
3530 * ```
3531 *
3532 * @category utility types
3533 * @since 2.0.0
3534 */
3535 export type AndNonEmpty<
3536 S extends Iterable<any>,
3537 T extends Iterable<any>,
3538 A
3539 > = S extends NonEmptyReadonlyArray<any> ? T extends NonEmptyReadonlyArray<any> ? NonEmptyArray<A>
3540 : Array<A>
3541 : Array<A>
3542
3543 /**
3544 * Flattens a nested array type.
3545 *
3546 * **Example** (Flattening nested array types)
3547 *
3548 * ```ts import.meta.vitest
3549 * import type { Array } from "effect"
3550 *
3551 * type Nested = ReadonlyArray<ReadonlyArray<number>>
3552 * type Flattened = Array.ReadonlyArray.Flatten<Nested>
3553 * // Flattened is Array<number>
3554 * ```
3555 *
3556 * @category utility types
3557 * @since 2.0.0
3558 */
3559 export type Flatten<T extends ReadonlyArray<ReadonlyArray<any>>> = T extends
3560 NonEmptyReadonlyArray<NonEmptyReadonlyArray<any>> ? NonEmptyArray<T[number][number]>
3561 : Array<T[number][number]>
3562}
3563
3564/**
3565 * Transforms each element using a function, returning a new array.
3566 *
3567 * **When to use**
3568 *
3569 * Use to transform each element independently while preserving the array shape.
3570 *
3571 * **Details**
3572 *
3573 * The function receives `(element, index)`. The return type preserves
3574 * `NonEmptyArray`.
3575 *
3576 * **Example** (Doubling values)
3577 *
3578 * ```ts import.meta.vitest
3579 * import { Array } from "effect"
3580 *
3581 * Array.map([1, 2, 3], (x) => x * 2) // => [2, 4, 6]
3582 * ```
3583 *
3584 * @see {@link flatMap} — map and flatten
3585 *
3586 * @category mapping
3587 * @since 2.0.0
3588 */
3589export const map: {
3590 <S extends ReadonlyArray<any>, B>(
3591 f: (a: ReadonlyArray.Infer<S>, i: number) => B
3592 ): (self: S) => ReadonlyArray.With<S, B>
3593 <S extends ReadonlyArray<any>, B>(self: S, f: (a: ReadonlyArray.Infer<S>, i: number) => B): ReadonlyArray.With<S, B>
3594} = dual(2, <A, B>(self: ReadonlyArray<A>, f: (a: A, i: number) => B): Array<B> => self.map(f))
3595
3596/**
3597 * Maps each element to an array and flattens the results into a single array.
3598 *
3599 * **When to use**
3600 *
3601 * Use to map each array element to zero or more values and concatenate the
3602 * results in one pass.
3603 *
3604 * **Details**
3605 *
3606 * The function receives `(element, index)`. This returns `NonEmptyArray` when
3607 * both the input and mapped arrays are non-empty.
3608 *
3609 * **Example** (Flat mapping an array)
3610 *
3611 * ```ts import.meta.vitest
3612 * import { Array } from "effect"
3613 *
3614 * Array.flatMap([1, 2, 3], (x) => [x, x * 2]) // => [1, 2, 2, 4, 3, 6]
3615 * ```
3616 *
3617 * @see {@link map} — transform without flattening
3618 * @see {@link flatten} — flatten without mapping
3619 *
3620 * @category sequencing
3621 * @since 2.0.0
3622 */
3623export const flatMap: {
3624 <S extends ReadonlyArray<any>, T extends ReadonlyArray<any>>(
3625 f: (a: ReadonlyArray.Infer<S>, i: number) => T
3626 ): (self: S) => ReadonlyArray.AndNonEmpty<S, T, ReadonlyArray.Infer<T>>
3627 <A, B>(self: NonEmptyReadonlyArray<A>, f: (a: A, i: number) => NonEmptyReadonlyArray<B>): NonEmptyArray<B>
3628 <A, B>(self: ReadonlyArray<A>, f: (a: A, i: number) => ReadonlyArray<B>): Array<B>
3629} = dual(
3630 2,
3631 <A, B>(self: ReadonlyArray<A>, f: (a: A, i: number) => ReadonlyArray<B>): Array<B> => {
3632 if (isReadonlyArrayEmpty(self)) {
3633 return []
3634 }
3635 const out: Array<B> = []
3636 for (let i = 0; i < self.length; i++) {
3637 const inner = f(self[i], i)
3638 for (let j = 0; j < inner.length; j++) {
3639 out.push(inner[j])
3640 }
3641 }
3642 return out
3643 }
3644)
3645
3646/**
3647 * Flattens a nested array of arrays into a single array.
3648 *
3649 * **When to use**
3650 *
3651 * Use to collapse one level of nested arrays when no per-element mapping is
3652 * needed.
3653 *
3654 * **Example** (Flattening nested arrays)
3655 *
3656 * ```ts import.meta.vitest
3657 * import { Array } from "effect"
3658 *
3659 * Array.flatten([[1, 2], [], [3, 4], [], [5, 6]]) // => [1, 2, 3, 4, 5, 6]
3660 * ```
3661 *
3662 * @see {@link flatMap} — map then flatten in one step
3663 *
3664 * @category sequencing
3665 * @since 2.0.0
3666 */
3667export const flatten: <const S extends ReadonlyArray<ReadonlyArray<any>>>(self: S) => ReadonlyArray.Flatten<S> =
3668 flatMap(identity) as any
3669
3670/**
3671 * Extracts all `Some` values from an iterable of `Option`s, discarding `None`s.
3672 *
3673 * **When to use**
3674 *
3675 * Use to collect only present values from an iterable of `Option` values while
3676 * discarding `None` values.
3677 *
3678 * **Example** (Extracting Some values)
3679 *
3680 * ```ts import.meta.vitest
3681 * import { Array, Option } from "effect"
3682 *
3683 * Array.getSomes([Option.some(1), Option.none(), Option.some(2)]) // => [1, 2]
3684 * ```
3685 *
3686 * @see {@link fromOption} — convert a single Option
3687 * @see {@link getSuccesses} — extract successes from Results
3688 *
3689 * @category filtering
3690 * @since 2.0.0
3691 */
3692
3693export const getSomes: <T extends Iterable<Option.Option<X>>, X = any>(
3694 self: T
3695) => Array<Option.Option.Value<ReadonlyArray.Infer<T>>> = (self: any) => {
3696 const out: Array<any> = []
3697 for (const a of self) {
3698 if (Option.isSome(a)) {
3699 out.push(a.value)
3700 }
3701 }
3702 return out
3703}
3704
3705/**
3706 * Extracts all failure values from an iterable of `Result`s, discarding
3707 * successes.
3708 *
3709 * **When to use**
3710 *
3711 * Use when you can drop the success channel and only need the failure
3712 * payloads, not the original result wrappers.
3713 *
3714 * **Example** (Extracting failures)
3715 *
3716 * ```ts import.meta.vitest
3717 * import { Array, Result } from "effect"
3718 *
3719 * Array.getFailures([Result.succeed(1), Result.fail("err"), Result.succeed(2)]) // => ["err"]
3720 * ```
3721 *
3722 * @see {@link getSuccesses} — extract success values
3723 * @see {@link separate} — split into successes and failures
3724 *
3725 * @category filtering
3726 * @since 4.0.0
3727 */
3728export const getFailures = <T extends Iterable<Result.Result<any, any>>>(
3729 self: T
3730): Array<Result.Result.Failure<ReadonlyArray.Infer<T>>> => {
3731 const out: Array<any> = []
3732 for (const a of self) {
3733 if (Result.isFailure(a)) {
3734 out.push(a.failure)
3735 }
3736 }
3737
3738 return out
3739}
3740
3741/**
3742 * Extracts all success values from an iterable of `Result`s, discarding
3743 * failures.
3744 *
3745 * **When to use**
3746 *
3747 * Use when you can drop the failure channel and only need the success
3748 * payloads, not the original result wrappers.
3749 *
3750 * **Example** (Extracting successes)
3751 *
3752 * ```ts import.meta.vitest
3753 * import { Array, Result } from "effect"
3754 *
3755 * Array.getSuccesses([Result.succeed(1), Result.fail("err"), Result.succeed(2)]) // => [1, 2]
3756 * ```
3757 *
3758 * @see {@link getFailures} — extract failure values
3759 * @see {@link separate} — split into successes and failures
3760 *
3761 * @category filtering
3762 * @since 4.0.0
3763 */
3764export const getSuccesses = <T extends Iterable<Result.Result<any, any>>>(
3765 self: T
3766): Array<Result.Result.Success<ReadonlyArray.Infer<T>>> => {
3767 const out: Array<any> = []
3768 for (const a of self) {
3769 if (Result.isSuccess(a)) {
3770 out.push(a.success)
3771 }
3772 }
3773
3774 return out
3775}
3776
3777/**
3778 * Keeps transformed values for elements where a `Filter` succeeds.
3779 *
3780 * **When to use**
3781 *
3782 * Use to filter an iterable with a `Result`-returning transformation while
3783 * discarding failures.
3784 *
3785 * **Details**
3786 *
3787 * The filter receives `(element, index)`. Failures are discarded.
3788 *
3789 * **Example** (Filtering and transforming)
3790 *
3791 * ```ts import.meta.vitest
3792 * import { Array, Result } from "effect"
3793 *
3794 * Array.filterMap([1, 2, 3, 4], (n) => n % 2 === 0 ? Result.succeed(n * 10) : Result.failVoid) // => [20, 40]
3795 * ```
3796 *
3797 * @see {@link filter} — keep original elements matching a predicate
3798 * @see {@link partition} for keeping both successes and failures
3799 *
3800 * @category filtering
3801 * @since 2.0.0
3802 */
3803export const filterMap: {
3804 <A, B, X>(f: (input: NoInfer<A>, i: number) => Result.Result<B, X>): (self: Iterable<A>) => Array<B>
3805 <A, B, X>(self: Iterable<A>, f: (input: A, i: number) => Result.Result<B, X>): Array<B>
3806} = dual(2, <A, B, X>(self: Iterable<A>, f: (input: A, i: number) => Result.Result<B, X>): Array<B> => {
3807 const as = fromIterable(self)
3808 const out: Array<B> = []
3809 for (let i = 0; i < as.length; i++) {
3810 const result = f(as[i], i)
3811 if (Result.isSuccess(result)) {
3812 out.push(result.success)
3813 }
3814 }
3815 return out
3816})
3817
3818/**
3819 * Keeps only elements satisfying a predicate (or refinement).
3820 *
3821 * **When to use**
3822 *
3823 * Use to filter an iterable into a new array of original elements that satisfy
3824 * a boolean predicate or refinement.
3825 *
3826 * **Details**
3827 *
3828 * The predicate receives `(element, index)`. Refinements are supported for type
3829 * narrowing.
3830 *
3831 * **Example** (Filtering even numbers)
3832 *
3833 * ```ts import.meta.vitest
3834 * import { Array } from "effect"
3835 *
3836 * Array.filter([1, 2, 3, 4], (x) => x % 2 === 0) // => [2, 4]
3837 * ```
3838 *
3839 * @see {@link partition} — split into matching and non-matching
3840 * @see {@link filterMap} for transforming while filtering
3841 *
3842 * @category filtering
3843 * @since 2.0.0
3844 */
3845export const filter: {
3846 <A, B extends A>(refinement: (a: NoInfer<A>, i: number) => a is B): (self: Iterable<A>) => Array<B>
3847 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => Array<A>
3848 <A, B extends A>(self: Iterable<A>, refinement: (a: A, i: number) => a is B): Array<B>
3849 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A>
3850} = dual(
3851 2,
3852 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): Array<A> => {
3853 const as = fromIterable(self)
3854 const out: Array<A> = []
3855 for (let i = 0; i < as.length; i++) {
3856 if (predicate(as[i], i)) {
3857 out.push(as[i])
3858 }
3859 }
3860 return out
3861 }
3862)
3863
3864/**
3865 * Splits an iterable using a `Filter` into successes and failures.
3866 *
3867 * **When to use**
3868 *
3869 * Use to partition an iterable by evaluating each element with a
3870 * `Result`-returning filter and keeping both success and failure values.
3871 *
3872 * **Details**
3873 *
3874 * Returns `[passes, fails]`. The filter receives `(element, index)`.
3875 *
3876 * **Example** (Partitioning with a filter)
3877 *
3878 * ```ts import.meta.vitest
3879 * import { Array, Result } from "effect"
3880 *
3881 * Array.partition([1, -2, 3], (n, i) =>
3882 * n > 0 ? Result.succeed(n + i) : Result.fail(`negative:${n}`)
3883 * ) // => [[1, 5], ["negative:-2"]]
3884 * ```
3885 *
3886 * @see {@link filter} — keep only matching elements
3887 * @see {@link filterMap} for discarding failures
3888 * @see {@link separate} — split an iterable of `Result` values
3889 *
3890 * @category filtering
3891 * @since 2.0.0
3892 */
3893export const partition: {
3894 <A, Pass, Fail>(
3895 f: (input: NoInfer<A>, i: number) => Result.Result<Pass, Fail>
3896 ): (self: Iterable<A>) => [passes: Array<Pass>, fails: Array<Fail>]
3897 <A, Pass, Fail>(
3898 self: Iterable<A>,
3899 f: (input: A, i: number) => Result.Result<Pass, Fail>
3900 ): [passes: Array<Pass>, fails: Array<Fail>]
3901} = dual(
3902 2,
3903 <A, Pass, Fail>(
3904 self: Iterable<A>,
3905 f: (input: A, i: number) => Result.Result<Pass, Fail>
3906 ): [passes: Array<Pass>, fails: Array<Fail>] => {
3907 const passes: Array<Pass> = []
3908 const fails: Array<Fail> = []
3909 let i = 0
3910 for (const a of self) {
3911 const result = f(a, i++)
3912 if (Result.isSuccess(result)) {
3913 passes.push(result.success)
3914 } else {
3915 fails.push(result.failure)
3916 }
3917 }
3918 return [passes, fails]
3919 }
3920)
3921
3922/**
3923 * Separates an iterable of `Result`s into success values and failure values.
3924 *
3925 * **When to use**
3926 *
3927 * Use to split an iterable of `Result` values into success and failure arrays.
3928 *
3929 * **Details**
3930 *
3931 * Returns `[successes, failures]`. This is equivalent to
3932 * `partition(identity)`.
3933 *
3934 * **Example** (Separating Results)
3935 *
3936 * ```ts import.meta.vitest
3937 * import { Array, Result } from "effect"
3938 *
3939 * Array.separate([Result.succeed(1), Result.fail("error"), Result.succeed(2)]) // => [[1, 2], ["error"]]
3940 * ```
3941 *
3942 * @see {@link getFailures} — extract only failures
3943 * @see {@link getSuccesses} — extract only successes
3944 * @see {@link partition} for computing `Result` values while splitting
3945 *
3946 * @category filtering
3947 * @since 2.0.0
3948 */
3949export const separate: <T extends Iterable<Result.Result<any, any>>>(
3950 self: T
3951) => [
3952 successes: Array<Result.Result.Success<ReadonlyArray.Infer<T>>>,
3953 failures: Array<Result.Result.Failure<ReadonlyArray.Infer<T>>>
3954] = partition(identity)
3955
3956/**
3957 * Folds an iterable from left to right into a single value.
3958 *
3959 * **When to use**
3960 *
3961 * Use to combine all elements into one accumulated value from left to right.
3962 *
3963 * **Details**
3964 *
3965 * The function receives `(accumulator, element, index)`.
3966 *
3967 * **Example** (Summing an array)
3968 *
3969 * ```ts import.meta.vitest
3970 * import { Array } from "effect"
3971 *
3972 * Array.reduce([1, 2, 3], 0, (acc, n) => acc + n) // => 6
3973 * ```
3974 *
3975 * @see {@link reduceRight} — fold from right to left
3976 * @see {@link scan} — fold keeping intermediate values
3977 *
3978 * @category folding
3979 * @since 2.0.0
3980 */
3981export const reduce: {
3982 <B, A>(b: B, f: (b: B, a: A, i: number) => B): (self: Iterable<A>) => B
3983 <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A, i: number) => B): B
3984} = dual(
3985 3,
3986 <B, A>(self: Iterable<A>, b: B, f: (b: B, a: A, i: number) => B): B =>
3987 fromIterable(self).reduce((b, a, i) => f(b, a, i), b)
3988)
3989
3990/**
3991 * Folds an iterable from right to left into a single value.
3992 *
3993 * **When to use**
3994 *
3995 * Use when you need to fold values from right to left.
3996 *
3997 * **Details**
3998 *
3999 * The function receives `(accumulator, element, index)`.
4000 *
4001 * **Example** (Folding from right to left)
4002 *
4003 * ```ts import.meta.vitest
4004 * import { Array } from "effect"
4005 *
4006 * Array.reduceRight([1, 2, 3], 0, (acc, n) => acc + n) // => 6
4007 * ```
4008 *
4009 * @see {@link reduce} — fold from left to right
4010 * @see {@link scanRight} — fold keeping intermediate values
4011 *
4012 * @category folding
4013 * @since 2.0.0
4014 */
4015export const reduceRight: {
4016 <B, A>(b: B, f: (b: B, a: A, i: number) => B): (self: Iterable<A>) => B
4017 <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A, i: number) => B): B
4018} = dual(
4019 3,
4020 <A, B>(self: Iterable<A>, b: B, f: (b: B, a: A, i: number) => B): B =>
4021 fromIterable(self).reduceRight((b, a, i) => f(b, a, i), b)
4022)
4023
4024/**
4025 * Lifts a predicate into an array: returns `[value]` if the predicate holds,
4026 * `[]` otherwise.
4027 *
4028 * **Example** (Wrapping values conditionally)
4029 *
4030 * ```ts import.meta.vitest
4031 * import { Array } from "effect"
4032 *
4033 * const fromEven = Array.liftPredicate((n: number) => n % 2 === 0)
4034 *
4035 * fromEven(1) // => []
4036 * fromEven(2) // => [2]
4037 * ```
4038 *
4039 * @see {@link liftOption} — lift an Option-returning function
4040 *
4041 * @category lifting
4042 * @since 2.0.0
4043 */
4044export const liftPredicate: { // Note: I intentionally avoid using the NoInfer pattern here.
4045 <A, B extends A>(refinement: Predicate.Refinement<A, B>): (a: A) => Array<B>
4046 <A>(predicate: Predicate.Predicate<A>): <B extends A>(b: B) => Array<B>
4047} = <A>(predicate: Predicate.Predicate<A>) => <B extends A>(b: B): Array<B> => predicate(b) ? [b] : []
4048
4049/**
4050 * Lifts an `Option`-returning function into one that returns an array:
4051 * `Some(a)` becomes `[a]`, `None` becomes `[]`.
4052 *
4053 * **When to use**
4054 *
4055 * Use when an optional parser or lookup should participate in array pipelines
4056 * as zero-or-one results.
4057 *
4058 * **Example** (Lifting an Option function)
4059 *
4060 * ```ts import.meta.vitest
4061 * import { Array, Option } from "effect"
4062 *
4063 * const parseNumber = Array.liftOption((s: string) => {
4064 * const n = Number(s)
4065 * return isNaN(n) ? Option.none() : Option.some(n)
4066 * })
4067 *
4068 * parseNumber("123") // => [123]
4069 * parseNumber("abc") // => []
4070 * ```
4071 *
4072 * @see {@link liftPredicate} — lift a boolean predicate
4073 * @see {@link liftResult} — lift a Result-returning function
4074 *
4075 * @category lifting
4076 * @since 2.0.0
4077 */
4078export const liftOption = <A extends Array<unknown>, B>(
4079 f: (...a: A) => Option.Option<B>
4080) =>
4081(...a: A): Array<B> => fromOption(f(...a))
4082
4083/**
4084 * Converts a nullable value to an array: `null`/`undefined` becomes `[]`,
4085 * anything else becomes `[value]`.
4086 *
4087 * **When to use**
4088 *
4089 * Use to treat a nullable single value as zero or one array element.
4090 *
4091 * **Example** (Converting nullable values to an array)
4092 *
4093 * ```ts import.meta.vitest
4094 * import { Array } from "effect"
4095 *
4096 * Array.fromNullishOr(1) // => [1]
4097 * Array.fromNullishOr(null) // => []
4098 * Array.fromNullishOr(undefined) // => []
4099 * ```
4100 *
4101 * @see {@link liftNullishOr} — lift a nullable-returning function
4102 * @see {@link fromOption} — convert from Option
4103 *
4104 * @category converting
4105 * @since 4.0.0
4106 */
4107export const fromNullishOr = <A>(a: A): Array<NonNullable<A>> => a == null ? empty() : [a as NonNullable<A>]
4108
4109/**
4110 * Lifts a nullable-returning function into one that returns an array:
4111 * `null`/`undefined` becomes `[]`, anything else becomes `[value]`.
4112 *
4113 * **Example** (Lifting a nullable function)
4114 *
4115 * ```ts import.meta.vitest
4116 * import { Array } from "effect"
4117 *
4118 * const parseNumber = Array.liftNullishOr((s: string) => {
4119 * const n = Number(s)
4120 * return isNaN(n) ? null : n
4121 * })
4122 *
4123 * parseNumber("123") // => [123]
4124 * parseNumber("abc") // => []
4125 * ```
4126 *
4127 * @see {@link fromNullishOr} — convert a single nullable value
4128 * @see {@link liftOption} — lift an Option-returning function
4129 *
4130 * @category lifting
4131 * @since 4.0.0
4132 */
4133export const liftNullishOr = <A extends Array<unknown>, B>(
4134 f: (...a: A) => B
4135): (...a: A) => Array<NonNullable<B>> =>
4136(...a) => fromNullishOr(f(...a))
4137
4138/**
4139 * Maps each element with a nullable-returning function, keeping only non-null /
4140 * non-undefined results.
4141 *
4142 * **When to use**
4143 *
4144 * Use when you need to map and filter in one step, where the mapper can return
4145 * `null` or `undefined` to skip elements.
4146 *
4147 * **Example** (Flat mapping with nullable values)
4148 *
4149 * ```ts import.meta.vitest
4150 * import { Array } from "effect"
4151 *
4152 * Array.flatMapNullishOr([1, 2, 3], (n) => (n % 2 === 0 ? null : n)) // => [1, 3]
4153 * ```
4154 *
4155 * @see {@link flatMap} for mapping each element to an array and flattening
4156 * @see {@link fromNullishOr} for converting a single nullable value to an array
4157 *
4158 * @category sequencing
4159 * @since 4.0.0
4160 */
4161export const flatMapNullishOr: {
4162 <A, B>(f: (a: A) => B): (self: ReadonlyArray<A>) => Array<NonNullable<B>>
4163 <A, B>(self: ReadonlyArray<A>, f: (a: A) => B): Array<NonNullable<B>>
4164} = dual(
4165 2,
4166 <A, B>(self: ReadonlyArray<A>, f: (a: A) => B): Array<NonNullable<B>> => flatMap(self, (a) => fromNullishOr(f(a)))
4167)
4168
4169/**
4170 * Lifts a `Result`-returning function into one that returns an array: failures
4171 * produce `[]`, successes produce `[value]`.
4172 *
4173 * **When to use**
4174 *
4175 * Use when a fallible parser or lookup should participate in array pipelines as
4176 * zero-or-one results and the failure value should be discarded.
4177 *
4178 * **Example** (Lifting a Result function)
4179 *
4180 * ```ts import.meta.vitest
4181 * import { Array, Result } from "effect"
4182 *
4183 * const parseNumber = (s: string): Result.Result<number, Error> =>
4184 * isNaN(Number(s))
4185 * ? Result.fail(new Error("Not a number"))
4186 * : Result.succeed(Number(s))
4187 *
4188 * const liftedParseNumber = Array.liftResult(parseNumber)
4189 *
4190 * liftedParseNumber("42") // => [42]
4191 * liftedParseNumber("not a number") // => []
4192 * ```
4193 *
4194 * @see {@link liftOption} — lift an Option-returning function
4195 * @see {@link liftPredicate} — lift a boolean predicate
4196 *
4197 * @category lifting
4198 * @since 4.0.0
4199 */
4200export const liftResult = <A extends Array<unknown>, E, B>(
4201 f: (...a: A) => Result.Result<B, E>
4202) =>
4203(...a: A): Array<B> => {
4204 const e = f(...a)
4205 return Result.isFailure(e) ? [] : [e.success]
4206}
4207
4208/**
4209 * Checks whether all elements satisfy the predicate. Supports refinements for
4210 * type narrowing.
4211 *
4212 * **When to use**
4213 *
4214 * Use to check whether every array element satisfies a predicate, including
4215 * refinement-based type narrowing.
4216 *
4217 * **Example** (Testing all elements)
4218 *
4219 * ```ts import.meta.vitest
4220 * import { Array } from "effect"
4221 *
4222 * Array.every([2, 4, 6], (x) => x % 2 === 0) // => true
4223 * Array.every([2, 3, 6], (x) => x % 2 === 0) // => false
4224 * ```
4225 *
4226 * @see {@link some} — test if any element matches
4227 *
4228 * @category guards
4229 * @since 2.0.0
4230 */
4231export const every: {
4232 <A, B extends A>(
4233 refinement: (a: NoInfer<A>, i: number) => a is B
4234 ): (self: ReadonlyArray<A>) => self is ReadonlyArray<B>
4235 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: ReadonlyArray<A>) => boolean
4236 <A, B extends A>(self: ReadonlyArray<A>, refinement: (a: A, i: number) => a is B): self is ReadonlyArray<B>
4237 <A>(self: ReadonlyArray<A>, predicate: (a: A, i: number) => boolean): boolean
4238} = dual(
4239 2,
4240 <A, B extends A>(self: ReadonlyArray<A>, refinement: (a: A, i: number) => a is B): self is ReadonlyArray<B> =>
4241 self.every(refinement)
4242)
4243
4244/**
4245 * Checks whether at least one element satisfies the predicate. Narrows the type
4246 * to `NonEmptyReadonlyArray` on success.
4247 *
4248 * **Example** (Testing for any match)
4249 *
4250 * ```ts import.meta.vitest
4251 * import { Array } from "effect"
4252 *
4253 * Array.some([1, 3, 4], (x) => x % 2 === 0) // => true
4254 * Array.some([1, 3, 5], (x) => x % 2 === 0) // => false
4255 * ```
4256 *
4257 * @see {@link every} — test if all elements match
4258 * @see {@link contains} — test for a specific value
4259 *
4260 * @category guards
4261 * @since 2.0.0
4262 */
4263export const some: {
4264 <A>(
4265 predicate: (a: NoInfer<A>, i: number) => boolean
4266 ): (self: ReadonlyArray<A>) => self is NonEmptyReadonlyArray<A>
4267 <A>(self: ReadonlyArray<A>, predicate: (a: A, i: number) => boolean): self is NonEmptyReadonlyArray<A>
4268} = dual(
4269 2,
4270 <A>(self: ReadonlyArray<A>, predicate: (a: A, i: number) => boolean): self is NonEmptyReadonlyArray<A> =>
4271 self.some(predicate)
4272)
4273
4274/**
4275 * Applies a function to each suffix of the array (starting from each index),
4276 * collecting the results.
4277 *
4278 * **When to use**
4279 *
4280 * Use when you need to compute a result from every suffix of an array, such as
4281 * cumulative aggregations from each position.
4282 *
4283 * **Details**
4284 *
4285 * For index `i`, the function receives `self.slice(i)`.
4286 *
4287 * **Example** (Computing suffix lengths)
4288 *
4289 * ```ts import.meta.vitest
4290 * import { Array } from "effect"
4291 *
4292 * Array.extend([1, 2, 3], (as) => as.length) // => [3, 2, 1]
4293 * ```
4294 *
4295 * @see {@link scan} for keeping intermediate accumulator values during a fold
4296 *
4297 * @category mapping
4298 * @since 2.0.0
4299 */
4300export const extend: {
4301 <A, B>(f: (as: ReadonlyArray<A>) => B): (self: ReadonlyArray<A>) => Array<B>
4302 <A, B>(self: ReadonlyArray<A>, f: (as: ReadonlyArray<A>) => B): Array<B>
4303} = dual(
4304 2,
4305 <A, B>(self: ReadonlyArray<A>, f: (as: ReadonlyArray<A>) => B): Array<B> => self.map((_, i, as) => f(as.slice(i)))
4306)
4307
4308/**
4309 * Returns the minimum element of a non-empty array according to the given
4310 * `Order`.
4311 *
4312 * **Example** (Finding the minimum)
4313 *
4314 * ```ts import.meta.vitest
4315 * import { Array, Order } from "effect"
4316 *
4317 * Array.min([3, 1, 2], Order.Number) // => 1
4318 * ```
4319 *
4320 * @see {@link max} — find the maximum
4321 * @see {@link sort} — sort the entire array
4322 *
4323 * @category getters
4324 * @since 2.0.0
4325 */
4326export const min: {
4327 <A>(O: Order.Order<A>): (self: NonEmptyReadonlyArray<A>) => A
4328 <A>(self: NonEmptyReadonlyArray<A>, O: Order.Order<A>): A
4329} = dual(2, <A>(self: NonEmptyReadonlyArray<A>, O: Order.Order<A>): A => self.reduce(Order.min(O)))
4330
4331/**
4332 * Returns the maximum element of a non-empty array according to the given
4333 * `Order`.
4334 *
4335 * **Example** (Finding the maximum)
4336 *
4337 * ```ts import.meta.vitest
4338 * import { Array, Order } from "effect"
4339 *
4340 * Array.max([3, 1, 2], Order.Number) // => 3
4341 * ```
4342 *
4343 * @see {@link min} — find the minimum
4344 * @see {@link sort} — sort the entire array
4345 *
4346 * @category getters
4347 * @since 2.0.0
4348 */
4349export const max: {
4350 <A>(O: Order.Order<A>): (self: NonEmptyReadonlyArray<A>) => A
4351 <A>(self: NonEmptyReadonlyArray<A>, O: Order.Order<A>): A
4352} = dual(2, <A>(self: NonEmptyReadonlyArray<A>, O: Order.Order<A>): A => self.reduce(Order.max(O)))
4353
4354/**
4355 * Builds an array by repeatedly applying a function to a seed value. The
4356 * function returns `Option.some([element, nextSeed])` to continue, or
4357 * `Option.none()` to stop.
4358 *
4359 * **Example** (Generating a sequence)
4360 *
4361 * ```ts import.meta.vitest
4362 * import { Array, Option } from "effect"
4363 *
4364 * Array.unfold(1, (n) => n <= 5 ? Option.some([n, n + 1]) : Option.none()) // => [1, 2, 3, 4, 5]
4365 * ```
4366 *
4367 * @see {@link makeBy} — generate from index
4368 * @see {@link range} — generate a numeric range
4369 *
4370 * @category constructors
4371 * @since 2.0.0
4372 */
4373export const unfold = <B, A>(b: B, f: (b: B) => Option.Option<readonly [A, B]>): Array<A> => {
4374 const out: Array<A> = []
4375 let next: B = b
4376 while (true) {
4377 const o = f(next)
4378 if (Option.isNone(o)) {
4379 break
4380 }
4381 const [a, b] = o.value
4382 out.push(a)
4383 next = b
4384 }
4385 return out
4386}
4387
4388/**
4389 * Creates an `Order` for arrays based on an element `Order`. Arrays are
4390 * compared element-wise; if all compared elements are equal, shorter arrays
4391 * come first.
4392 *
4393 * **Example** (Comparing arrays)
4394 *
4395 * ```ts import.meta.vitest
4396 * import { Array, Order } from "effect"
4397 *
4398 * const arrayOrder = Array.makeOrder(Order.Number)
4399 *
4400 * arrayOrder([1, 2], [1, 3]) // => -1
4401 * ```
4402 *
4403 * @see {@link makeEquivalence} — create an equivalence for arrays
4404 *
4405 * @category instances
4406 * @since 4.0.0
4407 */
4408export const makeOrder: <A>(O: Order.Order<A>) => Order.Order<ReadonlyArray<A>> = Order.Array
4409
4410/**
4411 * Creates an `Equivalence` for arrays based on an element `Equivalence`. Two
4412 * arrays are equivalent when they have the same length and all elements are
4413 * pairwise equivalent.
4414 *
4415 * **Example** (Comparing arrays for equality)
4416 *
4417 * ```ts import.meta.vitest
4418 * import { Array } from "effect"
4419 *
4420 * const eq = Array.makeEquivalence<number>((a, b) => a === b)
4421 *
4422 * eq([1, 2, 3], [1, 2, 3]) // => true
4423 * ```
4424 *
4425 * @see {@link makeOrder} — create an ordering for arrays
4426 *
4427 * @category instances
4428 * @since 4.0.0
4429 */
4430export const makeEquivalence: <A>(
4431 isEquivalent: Equivalence.Equivalence<A>
4432) => Equivalence.Equivalence<ReadonlyArray<A>> = Equivalence.Array
4433
4434/**
4435 * Runs a side-effect for each element. The callback receives `(element, index)`.
4436 *
4437 * **When to use**
4438 *
4439 * Use to iterate over an array for side-effects only, when no transformed
4440 * result is needed.
4441 *
4442 * **Example** (Iterating with side-effects)
4443 *
4444 * ```ts import.meta.vitest
4445 * import { Array } from "effect"
4446 *
4447 * const visited: Array<number> = []
4448 * Array.forEach([1, 2, 3], (n) => visited.push(n))
4449 *
4450 * visited // => [1, 2, 3]
4451 * ```
4452 *
4453 * @see {@link map} for transforming each element into a new array
4454 *
4455 * @category traversing
4456 * @since 2.0.0
4457 */
4458export const forEach: {
4459 <A>(f: (a: A, i: number) => void): (self: Iterable<A>) => void
4460 <A>(self: Iterable<A>, f: (a: A, i: number) => void): void
4461} = dual(2, <A>(self: Iterable<A>, f: (a: A, i: number) => void): void => fromIterable(self).forEach((a, i) => f(a, i)))
4462
4463/**
4464 * Removes duplicates using a custom equivalence, preserving the order of the
4465 * first occurrence.
4466 *
4467 * **When to use**
4468 *
4469 * Use to remove all duplicate elements with a custom equivalence when default
4470 * equality is not appropriate.
4471 *
4472 * **Example** (Deduplicating with custom equality)
4473 *
4474 * ```ts import.meta.vitest
4475 * import { Array } from "effect"
4476 *
4477 * Array.dedupeWith([1, 2, 2, 3, 3, 3], (a, b) => a === b) // => [1, 2, 3]
4478 * ```
4479 *
4480 * @see {@link dedupe} — uses default equality
4481 * @see {@link dedupeAdjacentWith} — only dedupes consecutive elements
4482 *
4483 * @category deduplication
4484 * @since 2.0.0
4485 */
4486export const dedupeWith: {
4487 <S extends Iterable<any>>(
4488 isEquivalent: (self: ReadonlyArray.Infer<S>, that: ReadonlyArray.Infer<S>) => boolean
4489 ): (self: S) => ReadonlyArray.With<S, ReadonlyArray.Infer<S>>
4490 <A>(self: NonEmptyReadonlyArray<A>, isEquivalent: (self: A, that: A) => boolean): NonEmptyArray<A>
4491 <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Array<A>
4492} = dual(
4493 2,
4494 <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Array<A> => {
4495 const out: Array<A> = []
4496 next: for (const r of fromIterable(self)) {
4497 for (let i = 0; i < out.length; i++) {
4498 if (isEquivalent(r, out[i])) continue next
4499 }
4500 out.push(r)
4501 }
4502 return out
4503 }
4504)
4505
4506/**
4507 * Removes duplicates using `Equal.equivalence()`, preserving the order of the
4508 * first occurrence.
4509 *
4510 * **When to use**
4511 *
4512 * Use to remove repeated values from an iterable when Effect's default equality
4513 * is the right comparison, preserving the first occurrence.
4514 *
4515 * **Example** (Removing duplicates)
4516 *
4517 * ```ts import.meta.vitest
4518 * import { Array } from "effect"
4519 *
4520 * Array.dedupe([1, 2, 1, 3, 2, 4]) // => [1, 2, 3, 4]
4521 * ```
4522 *
4523 * @see {@link dedupeWith} — use custom equality
4524 * @see {@link dedupeAdjacent} — only dedupes consecutive elements
4525 *
4526 * @category deduplication
4527 * @since 2.0.0
4528 */
4529export const dedupe = <S extends Iterable<any>>(
4530 self: S
4531): S extends NonEmptyReadonlyArray<infer A> ? NonEmptyArray<A> : S extends Iterable<infer A> ? Array<A> : never => {
4532 const input = fromIterable(self)
4533 if (input.length < 2) {
4534 return [...input] as any
4535 }
4536 const buckets: HashBuckets = new Map()
4537 const out: Array<unknown> = []
4538 for (const value of input) {
4539 if (hashBucketsAdd(buckets, value)) {
4540 out.push(value)
4541 }
4542 }
4543 return out as any
4544}
4545
4546/**
4547 * Removes consecutive duplicate elements using a custom equivalence.
4548 *
4549 * **When to use**
4550 *
4551 * Use when consecutive duplicates should be collapsed using a custom
4552 * equivalence, while equivalent values that appear later should remain in the
4553 * result.
4554 *
4555 * **Details**
4556 *
4557 * Non-adjacent duplicates are preserved.
4558 *
4559 * **Example** (Deduplicating adjacent elements)
4560 *
4561 * ```ts import.meta.vitest
4562 * import { Array } from "effect"
4563 *
4564 * Array.dedupeAdjacentWith([1, 1, 2, 2, 3, 3], (a, b) => a === b) // => [1, 2, 3]
4565 * ```
4566 *
4567 * @see {@link dedupeAdjacent} — uses default equality
4568 * @see {@link dedupeWith} — dedupes all duplicates, not just adjacent
4569 *
4570 * @category deduplication
4571 * @since 2.0.0
4572 */
4573export const dedupeAdjacentWith: {
4574 <A>(isEquivalent: (self: A, that: A) => boolean): (self: Iterable<A>) => Array<A>
4575 <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Array<A>
4576} = dual(2, <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Array<A> => {
4577 const out: Array<A> = []
4578 let lastA: Option.Option<A> = Option.none()
4579 for (const a of self) {
4580 if (Option.isNone(lastA) || !isEquivalent(a, lastA.value)) {
4581 out.push(a)
4582 lastA = Option.some(a)
4583 }
4584 }
4585 return out
4586})
4587
4588/**
4589 * Removes consecutive duplicate elements using `Equal.equivalence()`.
4590 *
4591 * **When to use**
4592 *
4593 * Use when you need to collapse consecutive duplicates while preserving later
4594 * non-consecutive repeats, and the default equality is sufficient.
4595 *
4596 * **Example** (Removing adjacent duplicates)
4597 *
4598 * ```ts import.meta.vitest
4599 * import { Array } from "effect"
4600 *
4601 * Array.dedupeAdjacent([1, 1, 2, 2, 3, 3]) // => [1, 2, 3]
4602 * ```
4603 *
4604 * @see {@link dedupeAdjacentWith} — use custom equality
4605 * @see {@link dedupe} — remove all duplicates
4606 *
4607 * @category deduplication
4608 * @since 2.0.0
4609 */
4610export const dedupeAdjacent: <A>(self: Iterable<A>) => Array<A> = dedupeAdjacentWith(Equal.asEquivalence())
4611
4612/**
4613 * Joins string elements with a separator.
4614 *
4615 * **Example** (Joining strings)
4616 *
4617 * ```ts import.meta.vitest
4618 * import { Array } from "effect"
4619 *
4620 * Array.join(["a", "b", "c"], "-") // => "a-b-c"
4621 * ```
4622 *
4623 * @see {@link intersperse} — insert separator elements without joining
4624 *
4625 * @category folding
4626 * @since 2.0.0
4627 */
4628export const join: {
4629 (sep: string): (self: Iterable<string>) => string
4630 (self: Iterable<string>, sep: string): string
4631} = dual(2, (self: Iterable<string>, sep: string): string => fromIterable(self).join(sep))
4632
4633/**
4634 * Maps over an array while threading an accumulator through each step, returning both the final state and the mapped array.
4635 *
4636 * **When to use**
4637 *
4638 * Use when you need to map while threading state through each element and keep
4639 * the final state.
4640 *
4641 * **Details**
4642 *
4643 * Combines `map` and `reduce` in a single pass. The callback receives the
4644 * current state, element, and index, and returns `[nextState, mappedValue]`.
4645 * The result is `[finalState, mappedArray]`. This can be used in both
4646 * data-first and data-last style.
4647 *
4648 * **Example** (Running sum alongside mapped values)
4649 *
4650 * ```ts import.meta.vitest
4651 * import { Array } from "effect"
4652 *
4653 * Array.mapAccum([1, 2, 3], 0, (acc, n) => [acc + n, acc + n]) // => [6, [1, 3, 6]]
4654 * ```
4655 *
4656 * @see {@link scan} — when you only need the accumulated results (not the final state)
4657 * @see {@link reduce} — when you only need the final accumulated value
4658 *
4659 * @category folding
4660 * @since 2.0.0
4661 */
4662export const mapAccum: {
4663 <S, A, B, I extends Iterable<A> = Iterable<A>>(
4664 s: S,
4665 f: (s: S, a: ReadonlyArray.Infer<I>, i: number) => readonly [S, B]
4666 ): (self: I) => [state: S, mappedArray: ReadonlyArray.With<I, B>]
4667 <S, A, B, I extends Iterable<A> = Iterable<A>>(
4668 self: I,
4669 s: S,
4670 f: (s: S, a: ReadonlyArray.Infer<I>, i: number) => readonly [S, B]
4671 ): [state: S, mappedArray: ReadonlyArray.With<I, B>]
4672} = dual(
4673 3,
4674 <S, A, B>(self: Iterable<A>, s: S, f: (s: S, a: A, i: number) => [S, B]): [state: S, mappedArray: Array<B>] => {
4675 let i = 0
4676 let s1 = s
4677 const out: Array<B> = []
4678 for (const a of self) {
4679 const r = f(s1, a, i)
4680 s1 = r[0]
4681 out.push(r[1])
4682 i++
4683 }
4684 return [s1, out]
4685 }
4686)
4687
4688/**
4689 * Computes the cartesian product of two arrays, applying a combiner to each pair.
4690 *
4691 * **When to use**
4692 *
4693 * Use to compute every combination from two arrays and immediately transform
4694 * each pair into a custom result.
4695 *
4696 * **Details**
4697 *
4698 * Produces every combination of an element from `self` with an element from
4699 * `that`, so the result length is `self.length * that.length`. Iteration visits
4700 * every element of `that` for each element of `self`.
4701 *
4702 * **Example** (Combining numbers and letters)
4703 *
4704 * ```ts import.meta.vitest
4705 * import { Array } from "effect"
4706 *
4707 * Array.cartesianWith([1, 2], ["a", "b"], (a, b) => `${a}-${b}`) // => ["1-a", "1-b", "2-a", "2-b"]
4708 * ```
4709 *
4710 * @see {@link cartesian} for returning tuples instead of applying a combiner
4711 *
4712 * @category combining
4713 * @since 2.0.0
4714 */
4715export const cartesianWith: {
4716 <A, B, C>(that: ReadonlyArray<B>, f: (a: A, b: B) => C): (self: ReadonlyArray<A>) => Array<C>
4717 <A, B, C>(self: ReadonlyArray<A>, that: ReadonlyArray<B>, f: (a: A, b: B) => C): Array<C>
4718} = dual(
4719 3,
4720 <A, B, C>(self: ReadonlyArray<A>, that: ReadonlyArray<B>, f: (a: A, b: B) => C): Array<C> =>
4721 flatMap(self, (a) => map(that, (b) => f(a, b)))
4722)
4723
4724/**
4725 * Computes the cartesian product of two arrays, returning all pairs as tuples.
4726 *
4727 * **When to use**
4728 *
4729 * Use when you need every `[a, b]` pair from two arrays as tuples.
4730 *
4731 * **Details**
4732 *
4733 * Produces every `[a, b]` combination of an element from `self` with an element
4734 * from `that`, so the result length is `self.length * that.length`.
4735 *
4736 * **Example** (Generating all pairs from two arrays)
4737 *
4738 * ```ts import.meta.vitest
4739 * import { Array } from "effect"
4740 *
4741 * Array.cartesian([1, 2], ["a", "b"]) // => [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
4742 * ```
4743 *
4744 * @see {@link cartesianWith} — apply a combiner to each pair
4745 *
4746 * @category combining
4747 * @since 2.0.0
4748 */
4749export const cartesian: {
4750 <B>(that: ReadonlyArray<B>): <A>(self: ReadonlyArray<A>) => Array<[A, B]>
4751 <A, B>(self: ReadonlyArray<A>, that: ReadonlyArray<B>): Array<[A, B]>
4752} = dual(
4753 2,
4754 <A, B>(self: ReadonlyArray<A>, that: ReadonlyArray<B>): Array<[A, B]> => cartesianWith(self, that, (a, b) => [a, b])
4755)
4756
4757// -------------------------------------------------------------------------------------
4758// do notation
4759// -------------------------------------------------------------------------------------
4760
4761/**
4762 * Provides the starting point for the "do simulation" — an array comprehension pattern.
4763 *
4764 * **When to use**
4765 *
4766 * Use when you want array-comprehension style code with do notation.
4767 *
4768 * **Details**
4769 *
4770 * Use {@link bind} to introduce array variables and {@link let_ let} for plain
4771 * values. Each `bind` produces the cartesian product of all bound variables,
4772 * like nested loops. Use `filter` and `map` in the pipeline to add conditions
4773 * and transformations.
4774 *
4775 * **Example** (Building array comprehensions with do notation)
4776 *
4777 * ```ts import.meta.vitest
4778 * import { Array, pipe } from "effect"
4779 *
4780 * pipe(
4781 * Array.Do,
4782 * Array.bind("x", () => [1, 3, 5]),
4783 * Array.bind("y", () => [2, 4, 6]),
4784 * Array.filter(({ x, y }) => x < y),
4785 * Array.map(({ x, y }) => [x, y] as const)
4786 * ) // => [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]]
4787 * ```
4788 *
4789 * @see {@link bind} — introduce an array variable into the scope
4790 * @see {@link bindTo} — start a pipeline by naming the first array
4791 * @see {@link let_ let} — introduce a plain computed value
4792 *
4793 * @category constructors
4794 * @since 3.2.0
4795 */
4796export const Do: ReadonlyArray<{}> = of({})
4797
4798/**
4799 * Adds a new array variable to a do-notation scope, producing the cartesian product with all previous bindings.
4800 *
4801 * **When to use**
4802 *
4803 * Use to add another array-producing binding to an `Array.Do` pipeline, pairing
4804 * each existing scope with every value returned by the callback.
4805 *
4806 * **Details**
4807 *
4808 * Each `bind` call adds a named property to the accumulated object. The
4809 * callback receives the current scope and must return an array. This is
4810 * equivalent to `flatMap` plus merging the new value into the scope object.
4811 *
4812 * **Example** (Binding two arrays)
4813 *
4814 * ```ts import.meta.vitest
4815 * import { Array, pipe } from "effect"
4816 *
4817 * pipe(
4818 * Array.Do,
4819 * Array.bind("x", () => [1, 2]),
4820 * Array.bind("y", () => ["a", "b"])
4821 * ) // => [{ x: 1, y: "a" }, { x: 1, y: "b" }, { x: 2, y: "a" }, { x: 2, y: "b" }]
4822 * ```
4823 *
4824 * @see {@link Do} — start a do-notation pipeline
4825 * @see {@link bindTo} — name the first array in a pipeline
4826 * @see {@link let_ let} — add a plain computed value
4827 *
4828 * @category sequencing
4829 * @since 3.2.0
4830 */
4831export const bind: {
4832 <A extends object, N extends string, B>(
4833 tag: Exclude<N, keyof A>,
4834 f: (a: NoInfer<A>) => ReadonlyArray<B>
4835 ): (
4836 self: ReadonlyArray<A>
4837 ) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }>
4838 <A extends object, N extends string, B>(
4839 self: ReadonlyArray<A>,
4840 tag: Exclude<N, keyof A>,
4841 f: (a: NoInfer<A>) => ReadonlyArray<B>
4842 ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }>
4843} = internalDoNotation.bind<ReadonlyArrayTypeLambda>(map, flatMap) as any
4844
4845/**
4846 * Wraps each array element in an object with the given key, starting a do-notation scope.
4847 *
4848 * **When to use**
4849 *
4850 * Use when you already have an array and want to start a do-notation pipeline
4851 * by naming each element.
4852 *
4853 * **Details**
4854 *
4855 * Equivalent to `Array.map(self, (a) => ({ [tag]: a }))`. This is an
4856 * alternative to starting with `Do` plus `bind` when you already have an array.
4857 *
4858 * **Example** (Naming an existing array)
4859 *
4860 * ```ts import.meta.vitest
4861 * import { Array } from "effect"
4862 *
4863 * Array.bindTo([1, 2, 3], "x") // => [{ x: 1 }, { x: 2 }, { x: 3 }]
4864 * ```
4865 *
4866 * @see {@link Do} — start with an empty scope
4867 * @see {@link bind} — add another array variable to the scope
4868 *
4869 * @category mapping
4870 * @since 3.2.0
4871 */
4872export const bindTo: {
4873 <N extends string>(tag: N): <A>(self: ReadonlyArray<A>) => Array<{ [K in N]: A }>
4874 <A, N extends string>(self: ReadonlyArray<A>, tag: N): Array<{ [K in N]: A }>
4875} = internalDoNotation.bindTo<ReadonlyArrayTypeLambda>(map) as any
4876
4877const let_: {
4878 <N extends string, B, A extends object>(
4879 tag: Exclude<N, keyof A>,
4880 f: (a: NoInfer<A>) => B
4881 ): (self: ReadonlyArray<A>) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }>
4882 <N extends string, A extends object, B>(
4883 self: ReadonlyArray<A>,
4884 tag: Exclude<N, keyof A>,
4885 f: (a: NoInfer<A>) => B
4886 ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }>
4887} = internalDoNotation.let_<ReadonlyArrayTypeLambda>(map) as any
4888
4889export {
4890 /**
4891 * Adds a computed plain value to the do-notation scope without introducing a new array dimension.
4892 *
4893 * **When to use**
4894 *
4895 * Use when each do-notation branch needs a derived field from the current
4896 * bindings without multiplying the number of branches.
4897 *
4898 * **Details**
4899 *
4900 * Unlike `bind`, the callback returns a single value instead of an array, so
4901 * no cartesian product occurs. Use this for derived or intermediate values
4902 * that depend on previously bound variables.
4903 *
4904 * **Example** (Adding a computed value)
4905 *
4906 * ```ts import.meta.vitest
4907 * import { Array, pipe } from "effect"
4908 *
4909 * pipe(
4910 * Array.Do,
4911 * Array.bind("x", () => [1, 2, 3]),
4912 * Array.let("doubled", ({ x }) => x * 2)
4913 * ) // => [{ x: 1, doubled: 2 }, { x: 2, doubled: 4 }, { x: 3, doubled: 6 }]
4914 * ```
4915 *
4916 * @see {@link Do} — start a do-notation pipeline
4917 * @see {@link bind} — introduce an array variable (produces cartesian product)
4918 *
4919 * @category mapping
4920 * @since 3.2.0
4921 */
4922 let_ as let
4923}
4924
4925const reducer = Reducer.make((a, b) => a.concat(b), [] as any)
4926
4927/**
4928 * Returns a `Reducer` that combines `ReadonlyArray` values by concatenation.
4929 *
4930 * @see {@link makeReducerConcat} — mutable `Array` variant
4931 *
4932 * @category folding
4933 * @since 4.0.0
4934 */
4935export function getReadonlyReducerConcat<A>(): Reducer.Reducer<ReadonlyArray<A>> {
4936 return reducer
4937}
4938
4939/**
4940 * Returns a `Reducer` that combines `Array` values by concatenation.
4941 *
4942 * @see {@link getReadonlyReducerConcat} — readonly variant
4943 *
4944 * @category folding
4945 * @since 4.0.0
4946 */
4947export function makeReducerConcat<A>(): Reducer.Reducer<Array<A>> {
4948 return reducer
4949}
4950
4951/**
4952 * Computes the number of elements in an iterable that satisfy a predicate.
4953 *
4954 * **When to use**
4955 *
4956 * Use when you need to count how many elements of an iterable satisfy a
4957 * predicate.
4958 *
4959 * **Details**
4960 *
4961 * The predicate receives both the element and its index. Empty iterables return
4962 * `0`.
4963 *
4964 * **Example** (Counting even numbers)
4965 *
4966 * ```ts import.meta.vitest
4967 * import { Array } from "effect"
4968 *
4969 * Array.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0) // => 2
4970 * ```
4971 *
4972 * @see {@link filter} — when you need the matching elements, not just the count
4973 *
4974 * @category folding
4975 * @since 3.16.0
4976 */
4977export const countBy: {
4978 <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => number
4979 <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): number
4980} = dual(
4981 2,
4982 <A>(
4983 self: Iterable<A>,
4984 f: (a: A, i: number) => boolean
4985 ): number => {
4986 let count = 0
4987 const as = fromIterable(self)
4988 for (let i = 0; i < as.length; i++) {
4989 const a = as[i]
4990 if (f(a, i)) {
4991 count++
4992 }
4993 }
4994 return count
4995 }
4996)