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;