import { getJoinSemigroup, getMeetSemigroup } from "@principia/prelude"; import type { Eq } from "@principia/prelude/Eq"; import type { Ord } from "@principia/prelude/Ord"; import * as A from "../Array"; import type { Option } from "../Option"; import type { ReadonlyRecord } from "../Record"; import type { NonEmptyArray } from "./model"; export const head = (as: NonEmptyArray): A => as[0]; export const tail = (as: NonEmptyArray): ReadonlyArray => as.slice(1); export const reverse: (as: NonEmptyArray) => NonEmptyArray = A.reverse as any; export const min = (O: Ord): ((as: NonEmptyArray) => A) => { const S = getMeetSemigroup(O); return (as) => as.reduce(S.combine_); }; export const max = (O: Ord): ((as: NonEmptyArray) => A) => { const S = getJoinSemigroup(O); return (as) => as.reduce(S.combine_); }; export function append_(xs: ReadonlyArray, ys: NonEmptyArray): NonEmptyArray; export function append_(xs: NonEmptyArray, ys: ReadonlyArray): NonEmptyArray; export function append_(xs: ReadonlyArray, ys: ReadonlyArray): ReadonlyArray { return A.append_(xs, ys); } export function append(ys: NonEmptyArray): (xs: ReadonlyArray) => NonEmptyArray; export function append(ys: ReadonlyArray): (xs: ReadonlyArray) => NonEmptyArray; export function append(ys: ReadonlyArray): (xs: ReadonlyArray) => ReadonlyArray { return (xs) => A.append_(xs, ys); } /** * Group equal, consecutive elements of an array into non empty arrays. * * @category Combinators * @since 1.0.0 */ export function group( E: Eq ): { (as: NonEmptyArray): NonEmptyArray>; (as: ReadonlyArray): ReadonlyArray>; }; export function group(E: Eq): (as: ReadonlyArray) => ReadonlyArray> { return (as) => { const len = as.length; if (len === 0) { return A.empty(); } const r: Array> = []; let head: A = as[0]; let nea: [A, ...ReadonlyArray] = [head]; for (let i = 1; i < len; i++) { const x = as[i]; if (E.equals_(x, head)) { nea.push(x); } else { r.push(nea); head = x; nea = [head]; } } r.push(nea); return r; }; } /** * Sort and then group the elements of an array into non empty arrays. * * @category Combinators * @since 1.0.0 */ export const groupSort = (O: Ord): ((as: ReadonlyArray) => ReadonlyArray>) => { const sortO = A.sort(O); const groupO = group(O); return (as) => groupO(sortO(as)); }; const _hasOwnProperty = Object.prototype.hasOwnProperty; /** * Splits an array into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning * function on each element, and grouping the results according to values returned * * @category Combinators * @since 1.0.0 */ export const groupBy = (f: (a: A) => string) => (as: ReadonlyArray): ReadonlyRecord> => { const r: Record]> = {}; for (const a of as) { const k = f(a); if (_hasOwnProperty.call(r, k)) { r[k].push(a); } else { r[k] = [a]; } } return r; }; /** * Get the last elements of a non empty array * * @since 1.0.0 */ export const last = (as: NonEmptyArray): A => as[as.length - 1]; /** * Get all but the last element of a non empty array, creating a new array. * * @since 1.0.0 */ export const init = (as: NonEmptyArray): ReadonlyArray => as.slice(0, -1); /** * @category Combinators * @since 1.0.0 */ export const sort = (O: Ord) => (as: NonEmptyArray): NonEmptyArray => A.sort(O)(as) as any; export const insertAt_ = (as: NonEmptyArray, i: number, a: A): Option> => A.insertAt_(as, i, a) as any; export const insertAt = (i: number, a: A) => (as: NonEmptyArray): Option> => insertAt_(as, i, a); export const updateAt_ = (as: NonEmptyArray, i: number, a: A): Option> => A.updateAt_(as, i, a) as any; export const updateAt = (i: number, a: A) => (as: NonEmptyArray): Option> => updateAt_(as, i, a); /** * Apply a function to the element at the specified index, creating a new array, or returning `None` if the index is out * of bounds * * @since 1.0.0 */ export const modifyAt_ = (as: NonEmptyArray, i: number, f: (a: A) => A): Option> => A.modifyAt_(as, i, f) as any; /** * Apply a function to the element at the specified index, creating a new array, or returning `None` if the index is out * of bounds * * @since 1.0.0 */ export const modifyAt = (i: number, f: (a: A) => A) => (as: NonEmptyArray): Option> => modifyAt_(as, i, f); /** * @since 1.0.0 */ export const unzip: ( as: NonEmptyArray ) => readonly [NonEmptyArray, NonEmptyArray] = A.unzip as any;