import type { AnyArray, Tail } from 'ts-essentials';
/**
 * Returns the tail of an array (all elements except the first one).
 */
export type TailOfArray<T extends unknown[]> = T extends [infer _, ...infer Rest] ? Rest : never;
/**
 * Returns the union of types in an array, but the first one, uses U as a fallback if the array is empty.
 */
export type TailTypesOrUndefined<T extends AnyArray, U = undefined> = T extends [] ? U : T extends [unknown] ? U : Tail<T>[number];
/**
 * Returns the union of types in an array, but the first and the second one, uses U as a fallback if the array is empty.
 */
export type Tail2TypesOrUndefined<T extends AnyArray, U = undefined> = T extends [] ? U : T extends [unknown] ? U : T extends [unknown, unknown] ? U : Tail<Tail<T>>[number];
/**
 * Returns the last element of an array
 */
export type LastOfArray<T extends AnyArray> = T extends [...infer _, infer L] ? L : never;
/**
 * Splits the array every time the given predicate fires.
 * The element the split appears on will not be included!
 * @example with this we can split on all empty strings:
 * ```
 * splitArrayOn(['a', '', 'b', '', '', 'c'], elem => elem === '')
 * // => [['a'], ['b'], [], ['c']]
 * ```
 * @example if the last element satisfies the predicate, this will add an empty array element
 * ```
 * splitArrayOn([1,2,3], elem => true)
 * // => [[], [], [], []]
 * ```
 */
export declare function splitArrayOn<T>(arr: readonly T[], predicate: (elem: T) => boolean): T[][];
/**
 * Returns a tuple of two arrays, where the first one contains all elements for which the predicate returned true,
 * and the second one contains all elements for which the predicate returned false.
 */
export declare function partitionArray<T>(arr: readonly T[], predicate: (elem: T) => boolean): [T[], T[]];
/**
 * Generate all permutations of the given array using Heap's algorithm (with its non-recursive variant).
 * @param arr - The array to permute
 * @see getUniqueCombinationsOfSize
 */
export declare function allPermutations<T>(arr: T[]): Generator<T[], void, void>;
/**
 * Returns a tuple of two arrays, where the first one contains all elements for which the predicate returned true,
 * and the second one contains all elements for which the predicate returned false.
 */
export declare function partition<T>(arr: T[], predicate: (elem: T) => boolean): [T[], T[]];
/**
 * Generate all unique combinations of the array with the given size.
 * In other words, given `[a,b,c]`, as well as `minSize=2` and `maxSize=2`, this will generate `[a,b]`, `[a,c]` and `[b,c]`,
 * but not, e.g., `[a,a]` or `[b,a]`.
 *
 * If `minSize!=maxSize`, the result is guaranteed to be sorted by size.
 * @param array   - The array to generate combinations from
 * @param minSize - The inclusive minimum size of the combinations, must be at least `0` and at most `maxSize`
 * @param maxSize - The inclusive maximum size of the combinations, must be at least `minSize` and at most `array.length`
 */
export declare function getUniqueCombinationsOfSize<T>(array: T[], minSize?: number, maxSize?: number): Generator<T[], void, void>;
/**
 * Returns the sum of all elements in the given array
 */
export declare function arraySum(arr: readonly number[]): number;
/**
 * Converts an array into a bag data-structure (in the form of a map mapping the entries/keys to their counts)
 */
export declare function array2bag<T>(arr: T[]): Map<T, number>;
/**
 * Compares two arrays for equality, using the given comparison function for the elements.
 */
export declare function arrayEqual<T>(a: readonly T[] | undefined, b: readonly T[] | undefined, cmp?: (a: T, b: T) => boolean): boolean;
/**
 * Samples elements from a list such that the distance between the sampled elements is as equal as possible.
 *
 * If the number of elements to sample is greater or equal to the number of elements in the list, the list is returned as is.
 * If the number of elements to sample is less than or equal to 0, an empty list is returned.
 * @param list - list of elements
 * @param sampleCount - number of elements to sample
 * @param rounding - rounding mode to use for the index calculation
 * @returns - a list of elements equidistantly sampled from the input list
 */
export declare function equidistantSampling<T>(list: readonly T[], sampleCount: number, rounding?: 'floor' | 'ceil'): T[];
/**
 * Returns the cartesian product of the given arrays.
 * @example
 *
 * ```ts
 * cartesianProduct([1, 2], ['a', 'b', 'c'], [true, false])
 * // -> [[1, 'a', true], [1, 'a', false], [1, 'b', true], [1, 'b', false], [1, 'c', true], [1, 'c', false], [2, 'a', true], [2, 'a', false], [2, 'b', true], [2, 'b', false], [2, 'c', true], [2, 'c', false]]
 * ```
 */
export declare function cartesianProduct<T>(...arrays: T[][]): T[][];
/** merge two arrays, removing duplicates */
export declare function uniqueArrayMerge<T>(left: readonly T[], right: readonly T[]): T[];
/**
 * Returns a duplicate-free array.
 */
export declare function uniqueArray<T>(a: Iterable<T>): T[];
/**
 * Groups the elements of the given array by the key returned by the given key function.
 */
export declare function arraysGroupBy<T, K>(arr: readonly T[], keyFn: (elem: T) => K): Map<K, T[]>;
