import type { NonEmptyArray, NonEmptyReadonlyArray } from "effect/Array" import * as Array from "effect/Array" import * as Chunk from "effect/Chunk" import * as Effect from "effect/Effect" import { dual, type Predicate } from "./Function.js" import * as Option from "./Option.js" export const toNonEmptyArray = Option.liftPredicate(Array.isReadonlyArrayNonEmpty) export const isArray: { // uses ReadonlyArray here because otherwise the second overload don't work when ROA is involved. (self: unknown): self is ReadonlyArray (self: T): self is Extract> } = Array.isArray export function NEAFromArray(ar: Array) { return ar.length ? Option.some(ar as NonEmptyArray) : Option.none() } export function NEROArrayFromArray(ar: ReadonlyArray) { return ar.length ? Option.some(ar as NonEmptyReadonlyArray) : Option.none() } export const groupByT = dual< ( f: (a: NoInfer) => Key ) => (as: ReadonlyArray) => Array]>, ( as: ReadonlyArray, f: (a: A) => Key ) => Array]> >(2, ( as: ReadonlyArray, f: (a: A) => Key ): Array]> => { const r = new Map>() for (const a of as) { const k = f(a) if (r.has(k)) { r.get(k)!.push(a) } else { r.set(k, [a]) } } return [...r.entries()] }) export const groupByTNonEmpty = dual< ( f: (a: NoInfer) => Key ) => (as: NonEmptyReadonlyArray) => NonEmptyArray]>, ( as: NonEmptyReadonlyArray, f: (a: A) => Key ) => NonEmptyArray]> >(2, ( as: NonEmptyReadonlyArray, f: (a: A) => Key ): NonEmptyArray]> => { const r = new Map>() for (const a of as) { const k = f(a) if (r.has(k)) { r.get(k)!.push(a) } else { r.set(k, [a]) } } return [...r.entries()] as unknown as NonEmptyArray]> }) // const a = [1, 2, 3] as const // const b = [1, 2, 3] // const a1 = groupByTNonEmpty(a, (x) => x % 2) // $ExpectType NonEmptyReadonlyArray]> // const b1 = groupByT(b, (x) => x % 2) // $ExpectType Array]> export function randomElement(a: NonEmptyReadonlyArray): A export function randomElement(a: ReadonlyArray): A | undefined export function randomElement(a: ReadonlyArray): A | undefined { return a[Math.floor(Math.random() * a.length)] } export function filterWith(self: ReadonlyArray, predicates: ReadonlyArray>) { return self.filter((_) => predicates.every((f) => f(_))) } /** * Split the `items` array into multiple, smaller chunks of the given `size`. */ export function* _chunk_(items_: Iterable, size: number) { const items = [...items_] while (items.length) { yield items.splice(0, size) } } /** * Split the `items` array into multiple, smaller chunks of the given `size`. */ export function chunk_(items_: Iterable, size: number) { return Chunk.fromIterable(_chunk_(items_, size)) } export function forEachEffectNA(as: NonEmptyReadonlyArray, f: (a: A) => Effect.Effect) { return Effect.map(Effect.forEach(as, f), (_) => Option.getOrNull(toNonEmptyArray(_))) } export * from "effect/Array"