Array.ts overview
Extensions to the effect/Array module providing predicates, indexed search, cardinality matching, indexed (un)grouping, sorted-iterator merging/difference, and cycle-aware unfolding.
Mental model
Type<A>is justReadonlyArray<A>; functions never mutate the input.- All functions are curried, data-last — call as
pipe(self, MArray.fn(arg)). - Equality-based functions (e.g.
hasDuplicates,longestCommonSubArray,differenceSorted) compare withEqual.equals. The*Withvariants take an explicitEquivalence.
Common tasks
- Predicates:
hasLength,hasDuplicates,hasDuplicatesWith - Search:
findAll,extractFirst,getFromEnd,longestCommonSubArray - Pattern match:
match012 - Unsafe access:
unsafeGet,unsafeGetter - Modify by position:
modifyHead,modifyInit,modifyTail,modifyLast - Group / ungroup:
ungroup,groupByNum,groupBy - Split:
splitAtFromRight,splitNonEmptyAtFromRight - Map / reduce with short-circuit:
mapUnlessNone,mapUnlessLeft,reduceUnlessNone,reduceUnlessLeft - Sorted operations:
mergeSorted,differenceSorted - Construct:
unfold,unfoldNonEmpty,pad - Format:
removeEmptyAndJoin
Quickstart
Example (Common predicates and indexed search)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
import * as MPredicate from "@parischap/effect-lib/MPredicate"
console.log(MArray.hasDuplicates([1, 2, 2, 3])) // true
console.log(pipe([1, 2, 3, 2], MArray.findAll(MPredicate.strictEquals(2)))) // [1, 3]
Exports Grouped by Category
Constructors
unfold
Curried version of Array.unfold with optional cycle detection.
- Without
seedEquivalence, behaves like a curriedArray.unfold: keep generating untilfreturnsOption.none. - With
seedEquivalence, every seed is recorded; if the same seed reappears,cycleSourceis asomeof theAproduced the first time that seed was processed, allowing the caller to break the cycle.
Example (Unfold without cycle detection)
import { Option, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const result = pipe(
0,
MArray.unfold((n) => (n < 3 ? Option.some([n, n + 1] as const) : Option.none()))
)
console.log(result) // [0, 1, 2]
See
MIterable.unfold— lazy counterpart
Signature
declare const unfold: {
<S, A>(f: (s: S) => Option.Option<MTypes.Pair<A, S>>): (s: S) => Array<A>
<S, A>(
f: (s: S, cycleSource: Option.Option<NoInfer<A>>) => Option.Option<MTypes.Pair<A, S>>,
seedEquivalence: Equivalence.Equivalence<S>
): (s: S) => Array<A>
}
unfoldNonEmpty
Variant of unfold where each step always produces an A and optionally a next seed S, guaranteeing a non-empty result.
- Use when at least one element must be produced.
- Cycle detection works the same way as in
unfold.
Example (Unfold a non-empty array)
import { Option, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const result = pipe(
0,
MArray.unfoldNonEmpty((n) => [n, n < 2 ? Option.some(n + 1) : Option.none()] as const)
)
console.log(result) // [0, 1, 2]
See
unfold— variant returning a possibly empty array
Signature
declare const unfoldNonEmpty: {
<S, A>(f: (s: S) => MTypes.Pair<A, Option.Option<S>>): (s: S) => MTypes.OverOne<A>
<S, A>(
f: (s: S, cycleSource: Option.Option<NoInfer<A>>) => MTypes.Pair<A, Option.Option<S>>,
seedEquivalence: Equivalence.Equivalence<S>
): (s: S) => MTypes.OverOne<A>
}
Destructors
getter
Returns a function that retrieves the element at a given index from self, wrapped in an Option.
- Use to precompute a getter once when the same array will be queried many times.
- The returned function is curried for the index and returns
Option.nonefor out-of-bounds accesses.
Example (Reusable safe getter)
import * as MArray from "@parischap/effect-lib/MArray"
const get = MArray.getter([1, 2, 3])
console.log(get(0)) // Some(1)
console.log(get(5)) // None
Signature
declare const getter: <A>(self: Type<A>) => MTypes.OneArgFunction<number, Option.Option<A>>
mapUnlessLeft
Maps every element of self with f, returning Result.success of the mapped array if every call succeeds, or the first failure encountered.
- Use when each step can produce a typed error.
- Short-circuits on the first failure returned by
f.
Example (Map with error handling)
import { Result, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const parseIntSafe = (s: string) => {
const n = parseInt(s)
return Number.isNaN(n) ? Result.fail(`Invalid number: ${s}`) : Result.succeed(n)
}
console.log(pipe(["1", "2", "3"], MArray.mapUnlessLeft(parseIntSafe))) // Success([1, 2, 3])
console.log(pipe(["1", "x", "3"], MArray.mapUnlessLeft(parseIntSafe))) // Failure('Invalid number: x')
See
mapUnlessNone— variant usingOption
Signature
declare const mapUnlessLeft: <S extends MTypes.AnyReadonlyArray, B, C>(
f: (a: Array.ReadonlyArray.Infer<S>, i: number) => Result.Result<B, C>
) => (self: S) => Result.Result<Array.ReadonlyArray.With<S, B>, C>
mapUnlessNone
Maps every element of self with f, returning Option.some of the mapped array if every call succeeds, or Option.none as soon as one call returns Option.none.
- Use when every element must be mappable for the operation to make sense.
- Short-circuits on the first
Option.nonereturned byf.
Example (Map with possible failure)
import { Option, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const safeDiv = (x: number) => (x !== 0 ? Option.some(10 / x) : Option.none())
console.log(pipe([2, 5], MArray.mapUnlessNone(safeDiv))) // Some([5, 2])
console.log(pipe([2, 0, 5], MArray.mapUnlessNone(safeDiv))) // None
See
mapUnlessLeft— variant carrying an explicit error
Signature
declare const mapUnlessNone: <S extends MTypes.AnyReadonlyArray, B>(
f: (a: Array.ReadonlyArray.Infer<S>, i: number) => Option.Option<B>
) => (self: S) => Option.Option<Array.ReadonlyArray.With<S, B>>
reduceUnlessLeft
Reduces self with f, returning Result.success of the final accumulator if every step succeeds, or the first failure encountered.
- Use when reducing with a step that can produce a typed error.
- Short-circuits on the first failure.
Example (Reduce with error handling)
import { Result, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const safeSum = (acc: number, x: string) => {
const n = parseInt(x)
return Number.isNaN(n) ? Result.fail(`Invalid: ${x}`) : Result.succeed(acc + n)
}
console.log(pipe(["1", "2", "3"], MArray.reduceUnlessLeft(0, safeSum))) // Success(6)
console.log(pipe(["1", "x", "3"], MArray.reduceUnlessLeft(0, safeSum))) // Failure('Invalid: x')
See
reduceUnlessNone— variant usingOption
Signature
declare const reduceUnlessLeft: <B, A, C>(
b: B,
f: (b: B, a: A, i: number) => Result.Result<B, C>
) => (self: Iterable<A>) => Result.Result<B, C>
reduceUnlessNone
Reduces self with f, returning Option.some of the final accumulator if every step succeeds, or Option.none as soon as one step returns Option.none.
- Use when reducing with a step that may fail without context.
- Short-circuits on the first
Option.none.
Example (Reduce with possible failure)
import { Option, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const safeAdd = (acc: number, x: number) => (x >= 0 ? Option.some(acc + x) : Option.none())
console.log(pipe([1, 2, 3], MArray.reduceUnlessNone(0, safeAdd))) // Some(6)
console.log(pipe([1, -1, 3], MArray.reduceUnlessNone(0, safeAdd))) // None
See
reduceUnlessLeft— variant carrying an explicit error
Signature
declare const reduceUnlessNone: <B, A>(
b: B,
f: (b: B, a: A, i: number) => Option.Option<B>
) => (self: Iterable<A>) => Option.Option<B>
unsafeGetter
Returns a function that retrieves the element of self at a given index without bounds checking.
- Use to precompute an unchecked getter when the same array will be queried many times under a bounds invariant.
- May return
undefined(typed asA) for out-of-bounds indexes.
Example (Reusable unsafe getter)
import * as MArray from "@parischap/effect-lib/MArray"
const get = MArray.unsafeGetter([1, 2, 3])
console.log(get(1)) // 2
See
getter— safe alternative returningOption
Signature
declare const unsafeGetter: <A>(self: Type<A>) => MTypes.OneArgFunction<number, A>
Models
Type (interface)
Type on which this module’s functions operate.
Signature
export interface Type<out A> extends ReadonlyArray<A> {}
Predicates
hasDuplicates
Returns true if self contains at least one duplicate, comparing elements with Equal.equals.
- Use to validate uniqueness with default equality.
- Comparison uses
effect/Equal.equals(structural equality forEqual-aware types, otherwise===).
Example (Detecting duplicates)
import * as MArray from "@parischap/effect-lib/MArray"
console.log(MArray.hasDuplicates([1, 2, 2, 3])) // true
console.log(MArray.hasDuplicates([1, 2, 3])) // false
See
hasDuplicatesWith— variant taking a customEquivalence
Signature
declare const hasDuplicates: (self: Type<unknown>) => boolean
hasDuplicatesWith
Returns true if self contains at least one duplicate, comparing elements with the supplied Equivalence.
- Use when default equality is not adequate (e.g. comparing objects by a single field).
- Returns
falsefor arrays with all-distinct elements.
Example (Detecting duplicates with a custom equivalence)
import { Equivalence, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const byId = Equivalence.mapInput(Equivalence.Number, (o: { readonly id: number }) => o.id)
console.log(pipe([{ id: 1 }, { id: 1 }], MArray.hasDuplicatesWith(byId))) // true
console.log(pipe([{ id: 1 }, { id: 2 }], MArray.hasDuplicatesWith(byId))) // false
See
hasDuplicates— variant usingEqual.equals
Signature
declare const hasDuplicatesWith: <A>(isEquivalent: Equivalence.Equivalence<NoInfer<A>>) => (self: Type<A>) => boolean
hasLength
Returns true if the length of self is exactly l.
- Use to assert that an array has a specific number of elements.
- Length comparison is
===.
Example (Length check)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3], MArray.hasLength(3))) // true
console.log(pipe([1, 2, 3], MArray.hasLength(2))) // false
Signature
declare const hasLength: (l: number) => <A>(self: Type<A>) => boolean
Utility types
With (type alias)
Utility type that replaces the type of every element of an array or tuple with A.
Signature
type With<S extends MTypes.AnyReadonlyArray, A> = { [k in keyof S]: A }
Utils
differenceSorted
Returns the elements of self not present in that. Both iterables must already be sorted according to o. Element equality is Equal.equals.
- Use to compute a sorted set difference in a single linear pass.
- Both inputs must be sorted; otherwise the result is undefined.
Example (Sorted difference)
import { Order, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3, 4, 5], MArray.differenceSorted(Order.Number)([2, 4]))) // [1, 3, 5]
See
MIterable.differenceSorted— lazy counterpart
Signature
declare const differenceSorted: <A>(o: Order.Order<A>) => (that: Iterable<A>) => (self: Iterable<A>) => Array<A>
extractFirst
Extracts the first element of self matching predicate (or refinement) and returns a pair of the extracted element (as an Option) and the remaining elements in their original order.
- Use to find and remove the first matching element in a single pass.
- When no element matches, returns
[Option.none(), self]. - Acts as a refinement-aware destructor: the extracted element is narrowed when a refinement is supplied.
Example (Extract first matching element)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const [match, rest] = pipe(
[1, 3, 2, 4],
MArray.extractFirst((n) => n > 2)
)
console.log(match) // Some(3)
console.log(rest) // [1, 2, 4]
Signature
declare const extractFirst: {
<A, B extends A>(
refinement: (a: NoInfer<A>, i: number) => a is B
): (self: Type<A>) => MTypes.Pair<Option.Option<B>, Array<A>>
<A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Type<A>) => MTypes.Pair<Option.Option<A>, Array<A>>
}
findAll
Returns the indexes of all elements of self satisfying predicate, in ascending order.
- Use to locate every position matching a condition.
- Returns an empty array when no element matches.
Example (Indexes of matching elements)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
import * as MPredicate from "@parischap/effect-lib/MPredicate"
console.log(pipe([1, 3, 2, 4], MArray.findAll(MPredicate.strictEquals(3)))) // [1]
console.log(pipe([1, 3, 2, 4, 3], MArray.findAll(MPredicate.strictEquals(3)))) // [1, 4]
See
MIterable.findAll— lazy counterpart
Signature
declare const findAll: <A>(predicate: Predicate.Predicate<NoInfer<A>>) => (self: Iterable<A>) => Array<number>
getFromEnd
Returns the element at position index counted from the end of self as an Option.
- Use to access from the tail of an array.
indexis zero-based:0is the last element.- Returns
Option.nonewhenindexis out of bounds.
Example (Indexed access from the end)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3], MArray.getFromEnd(0))) // Some(3)
console.log(pipe([1, 2, 3], MArray.getFromEnd(1))) // Some(2)
console.log(pipe([1, 2, 3], MArray.getFromEnd(3))) // None
Signature
declare const getFromEnd: (index: number) => <A>(self: Type<A>) => Option.Option<A>
groupBy
Like Array.groupBy but applies fValue to each element before collecting it into its bucket.
- Use to group and project in a single pass.
- Each bucket is guaranteed non-empty (typed
MTypes.OverOne<B>).
Example (Group with projection)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const data = [
{ type: "a", value: 1 },
{ type: "a", value: 2 },
{ type: "b", value: 3 }
] as const
console.log(pipe(data, MArray.groupBy({ fKey: (item) => item.type, fValue: (item) => item.value })))
// { a: [1, 2], b: [3] }
Signature
declare const groupBy: <A, B>({
fKey,
fValue
}: {
readonly fKey: (a: NoInfer<A>) => string
readonly fValue: (a: NoInfer<A>) => B
}) => (self: Iterable<A>) => Record<string, MTypes.OverOne<B>>
groupByNum
Maps the elements of self with fValue and groups the results by the numeric index returned by fKey. The output is an array of length size. Elements whose key is negative or >= size are dropped; rows for which no element maps are left as empty arrays.
- Use to bucket elements into a fixed number of slots.
- Together with
ungroupprovides a round-trip:groupByNumreversesungroup.
Example (Bucketing by row index)
import { Tuple, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const input = [
[0, "a"],
[0, "b"],
[1, "c"],
[1, "d"]
] as ReadonlyArray<[number, string]>
console.log(pipe(input, MArray.groupByNum({ size: 2, fKey: Tuple.get(0), fValue: Tuple.get(1) })))
// [['a', 'b'], ['c', 'd']]
See
ungroup— companion that produces[index, value]pairs
Signature
declare const groupByNum: <A, B>({
size,
fKey,
fValue
}: {
readonly size: number
readonly fKey: (a: NoInfer<A>) => number
readonly fValue: (a: NoInfer<A>) => B
}) => (self: Type<A>) => ReadonlyArray<ReadonlyArray<B>>
longestCommonSubArray
Returns the longest common prefix of self and that, comparing elements with Equal.equals.
- Use to find the leading elements two arrays agree on.
- Returns an empty array when the first elements already differ.
Example (Longest common prefix)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 4], MArray.longestCommonSubArray([1, 2, 3]))) // [1, 2]
console.log(pipe([0, 1], MArray.longestCommonSubArray([1, 2]))) // []
See
MIterable.longestCommonSubArray— lazy counterpart
Signature
declare const longestCommonSubArray: <A>(that: Iterable<A>) => (self: Iterable<A>) => Array<A>
match012
Pattern-matches self by cardinality: empty, singleton, or two-or-more.
- Use to branch type-safely on array size.
onSingletonreceives the single element directly.onOverTworeceivesselftyped asMTypes.ReadonlyOverTwo<A>(two-or-more).
Example (Cardinality match)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
const describe = MArray.match012<number, string, string, string>({
onEmpty: () => "empty",
onSingleton: (x: number) => `one: ${x}`,
onOverTwo: (xs) => `many: ${xs.length}`
})
console.log(pipe([], describe)) // 'empty'
console.log(pipe([1], describe)) // 'one: 1'
console.log(pipe([1, 2, 3], describe)) // 'many: 3'
Signature
declare const match012: <A, B, C = B, D = B>(options: {
readonly onEmpty: Function.LazyArg<B>
readonly onSingleton: (self: NoInfer<A>) => C
readonly onOverTwo: (self: MTypes.ReadonlyOverTwo<NoInfer<A>>) => D
}) => (self: Type<A>) => B | C | D
mergeSorted
Stably merges two iterables already sorted according to o.
- Both inputs must already be sorted by
o. - The merge is stable: equal elements from
selfprecede equal elements fromthat.
Example (Merge sorted iterables)
import { Order, pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 3, 5], MArray.mergeSorted(Order.Number)([2, 4, 6]))) // [1, 2, 3, 4, 5, 6]
See
MIterable.mergeSorted— lazy counterpart
Signature
declare const mergeSorted: <A>(o: Order.Order<A>) => (that: Iterable<A>) => (self: Iterable<A>) => Array<A>
modifyHead
Returns a copy of self with the first element transformed by f.
- Use to update only the leading element.
- Returns an empty copy when
selfis empty.
Example (Modify first element)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(
pipe(
[1, 2, 3],
MArray.modifyHead((x) => x * 2)
)
) // [2, 2, 3]
console.log(
pipe(
[],
MArray.modifyHead((x) => x * 2)
)
) // []
See
modifyLast— symmetric variant updating the last elementMIterable.modifyHead— lazy counterpart
Signature
declare const modifyHead: <S extends MTypes.AnyReadonlyArray, B>(
f: (a: Array.ReadonlyArray.Infer<S>) => B
) => (self: S) => With<S, Array.ReadonlyArray.Infer<S> | B>
modifyInit
Returns a copy of self with every element except the last transformed by f.
- Use to apply a transformation to all elements but the trailing one.
- Returns
selfunchanged when it has zero or one elements.
Example (Modify all but the last)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(
pipe(
[1, 2, 3, 4],
MArray.modifyInit((x) => x * 2)
)
) // [2, 4, 6, 4]
console.log(
pipe(
[5],
MArray.modifyInit((x) => x * 2)
)
) // [5]
See
modifyTail— symmetric variant keeping the head fixed
Signature
declare const modifyInit: <S extends MTypes.AnyReadonlyArray, B>(
f: (a: Array.ReadonlyArray.Infer<S>, i: number) => B
) => (self: S) => With<S, Array.ReadonlyArray.Infer<S> | B>
modifyLast
Returns a copy of self with the last element transformed by f.
- Use to update only the trailing element.
- Returns an empty copy when
selfis empty.
Example (Modify last element)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(
pipe(
[1, 2, 3],
MArray.modifyLast((x) => x * 2)
)
) // [1, 2, 6]
console.log(
pipe(
[],
MArray.modifyLast((x) => x * 2)
)
) // []
See
modifyHead— symmetric variant updating the first element
Signature
declare const modifyLast: <S extends MTypes.AnyReadonlyArray, B>(
f: (a: Array.ReadonlyArray.Infer<S>) => B
) => (self: S) => With<S, Array.ReadonlyArray.Infer<S> | B>
modifyTail
Returns a copy of self with every element except the first transformed by f.
- Use to apply a transformation to all elements but the leading one.
- Returns
selfunchanged when it has zero or one elements.
Example (Modify all but the first)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(
pipe(
[1, 2, 3, 4],
MArray.modifyTail((x) => x * 2)
)
) // [1, 4, 6, 8]
console.log(
pipe(
[5],
MArray.modifyTail((x) => x * 2)
)
) // [5]
See
modifyInit— symmetric variant keeping the last element fixedMIterable.modifyTail— lazy counterpart
Signature
declare const modifyTail: <S extends MTypes.AnyReadonlyArray, B>(
f: (a: Array.ReadonlyArray.Infer<S>, i: number) => B
) => (self: S) => With<S, Array.ReadonlyArray.Infer<S> | B>
pad
Same as Array.pad but the result is typed as a fixed-size Tuple of length N instead of a plain array.
- Use when the resulting length is part of the type and downstream code relies on it.
- Pads with
fillwhen shorter thann; truncates when longer.
Example (Padding to a fixed length)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3], MArray.pad(5, 0))) // [1, 2, 3, 0, 0]
Signature
declare const pad: <A, T, N extends number>(n: N, fill: T) => MTypes.OneArgFunction<Type<A>, Types.TupleOf<N, A | T>>
removeEmptyAndJoin
Joins the strings of self with sep, ignoring empty strings so they do not introduce extra separators.
- Use when assembling fragments coming from heterogeneous sources where some may be empty.
- The output never contains two consecutive
sep’s nor a leading/trailingsep.
Example (Joining without empty fragments)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe(["a", "", "b", "", "c"], MArray.removeEmptyAndJoin(", "))) // 'a, b, c'
Signature
declare const removeEmptyAndJoin: (sep: string) => MTypes.OneArgFunction<Iterable<string>, string>
splitAtFromRight
Splits self into two segments, the second containing at most the last n elements.
- Use to take a fixed-size suffix while keeping the rest.
- When
n >= self.length, the first segment is empty. nmust be a non-negative integer;0puts everything in the first segment.
Example (Split from the right)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3, 4, 5], MArray.splitAtFromRight(2))) // [[1, 2, 3], [4, 5]]
console.log(pipe([1, 2, 3], MArray.splitAtFromRight(0))) // [[1, 2, 3], []]
Signature
declare const splitAtFromRight: (n: number) => <A>(self: Type<A>) => [beforeIndex: Array<A>, fromIndex: Array<A>]
splitNonEmptyAtFromRight
Variant of splitAtFromRight for non-empty arrays where the second segment is guaranteed non-empty.
nmust be>= 1.- Returns the second segment typed as
MTypes.OverOne<A>.
Example (Non-empty split from the right)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3, 4] as const, MArray.splitNonEmptyAtFromRight(2))) // [[1, 2], [3, 4]]
Signature
declare const splitNonEmptyAtFromRight: (
n: number
) => <A>(self: MTypes.ReadonlyOverOne<A>) => [beforeIndex: Array<A>, fromIndex: MTypes.OverOne<A>]
takeBut
Returns all elements of self except the last n.
- Use to drop a suffix of fixed size.
- When
n >= self.length, returns an empty array. nshould be a non-negative integer.
Example (Drop trailing elements)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3, 4], MArray.takeBut(2))) // [1, 2]
console.log(pipe([1, 2, 3], MArray.takeBut(5))) // []
See
takeRightBut— symmetric variant dropping the leading elements
Signature
declare const takeBut: (n: number) => <A>(self: Type<A>) => Array<A>
takeRightBut
Returns all elements of self except the first n.
- Use to drop a prefix of fixed size.
- When
n >= self.length, returns an empty array. nshould be a non-negative integer.
Example (Drop leading elements)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3, 4], MArray.takeRightBut(2))) // [3, 4]
console.log(pipe([1, 2, 3], MArray.takeRightBut(5))) // []
See
takeBut— symmetric variant dropping the trailing elementsMIterable.takeRightBut— lazy counterpart
Signature
declare const takeRightBut: (n: number) => <A>(self: Type<A>) => Array<A>
ungroup
Flattens a two-dimensional array, tagging each element with the index of its source row.
- Use as the inverse companion to
groupByNum:groupByNumundoesungroupwhenfKey/fValueextract the row index and the original element respectively. - Order is preserved: rows are visited in order, and each row is flattened left to right.
Example (Tagged flatten)
import * as MArray from "@parischap/effect-lib/MArray"
console.log(
MArray.ungroup([
[1, 2, 3],
[4, 5]
])
)
// [[0, 1], [0, 2], [0, 3], [1, 4], [1, 5]]
See
groupByNum— reversesungroupMIterable.ungroup— lazy counterpart
Signature
declare const ungroup: <A>(as: Type<Type<A>>) => Array<[number, A]>
unsafeGet
Returns the element of self at index without bounds checking.
- Use only when bounds are guaranteed by construction; otherwise prefer
Array.get. - Returns
undefined(typed asA) for out-of-bounds indexes.
Example (Unchecked access)
import { pipe } from "effect"
import * as MArray from "@parischap/effect-lib/MArray"
console.log(pipe([1, 2, 3], MArray.unsafeGet(0))) // 1
console.log(pipe([1, 2, 3], MArray.unsafeGet(10))) // undefined
See
getter— safe alternative returningOption
Signature
declare const unsafeGet: (index: number) => <A>(self: Type<A>) => A