import type { AbortablePredicate, FalsyValue, Mapper, MutateOptions, Predicate, StringMap } from '../types.js';
/**
 * Creates an array of elements split into groups the length of size. If collection can’t be split evenly, the
 * final chunk will be the remaining elements.
 *
 * @param array The array to process.
 * @param size The length of each chunk.
 * @returns Returns the new array containing chunks.
 *
 * https://lodash.com/docs#chunk
 *
 * Based on: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_chunk
 */
export declare function _chunk<T>(array: readonly T[], size?: number): T[][];
/**
 * Removes duplicates from given array.
 */
export declare function _uniq<T>(a: readonly T[]): T[];
/**
 * Pushes an item to an array if it's not already there.
 * Mutates the array (same as normal `push`) and also returns it for chaining convenience.
 *
 * _pushUniq([1, 2, 3], 2) // => [1, 2, 3]
 *
 * Shortcut for:
 * if (!a.includes(item)) a.push(item)
 * // or
 * a = [...new Set(a).add(item)]
 * // or
 * a = _uniq([...a, item])
 */
export declare function _pushUniq<T>(a: T[], ...items: T[]): T[];
/**
 * Like _pushUniq but uses a mapper to determine uniqueness (like _uniqBy).
 * Mutates the array (same as normal `push`).
 */
export declare function _pushUniqBy<T>(a: T[], mapper: Mapper<T, any>, ...items: T[]): T[];
/**
 * This method is like `_.uniq` except that it accepts `iteratee` which is
 * invoked for each element in `array` to generate the criterion by which
 * uniqueness is computed. The iteratee is invoked with one argument: (value).
 *
 * @returns Returns the new duplicate free array.
 * @example
 *
 * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
 * // => [2.1, 1.2]
 *
 * // using the `_.property` iteratee shorthand
 * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
 * // => [{ 'x': 1 }, { 'x': 2 }]
 *
 * Based on: https://stackoverflow.com/a/40808569/4919972
 */
export declare function _uniqBy<T>(arr: readonly T[], mapper: Mapper<T, any>): T[];
/**
 * const a = [
 *  {id: 'id1', a: 'a1'},
 *  {id: 'id2', b: 'b1'},
 * ]
 *
 * _by(a, r => r.id)
 * // => {
 *   id1: {id: 'id1', a: 'a1'},
 *   id2: {id: 'id2', b: 'b1'},
 * }
 *
 * _by(a, r => r.id.toUpperCase())
 * // => {
 *   ID1: {id: 'id1', a: 'a1'},
 *   ID2: {id: 'id2', b: 'b1'},
 * }
 *
 * Returning `undefined` from the Mapper will EXCLUDE the item.
 */
export declare function _by<T>(items: readonly T[], mapper: Mapper<T, any>): StringMap<T>;
/**
 * Map an array of items by a key, that is calculated by a Mapper.
 */
export declare function _mapBy<ITEM, KEY>(items: readonly ITEM[], mapper: Mapper<ITEM, KEY>): Map<KEY, ITEM>;
/**
 * const a = [1, 2, 3, 4, 5]
 *
 * _groupBy(a, r => r % 2 ? 'even' : 'odd')
 * // => {
 *   odd: [1, 3, 5],
 *   even: [2, 4],
 * }
 *
 * Returning `undefined` from the Mapper will EXCLUDE the item.
 */
export declare function _groupBy<T>(items: readonly T[], mapper: Mapper<T, any>): StringMap<T[]>;
/**
 * Similar to `Array.find`, but the `predicate` may return `END` to stop the iteration early.
 *
 * Use `Array.find` if you don't need to stop the iteration early.
 */
export declare function _find<T>(items: readonly T[], predicate: AbortablePredicate<T>): T | undefined;
/**
 * Similar to `Array.findLast`, but the `predicate` may return `END` to stop the iteration early.
 *
 * Use `Array.findLast` if you don't need to stop the iteration early, which is supported:
 * - in Node since 18+
 * - in iOS Safari since 15.4
 */
export declare function _findLast<T>(items: readonly T[], predicate: AbortablePredicate<T>): T | undefined;
export declare function _takeWhile<T>(items: readonly T[], predicate: Predicate<T>): T[];
export declare function _takeRightWhile<T>(items: readonly T[], predicate: Predicate<T>): T[];
export declare function _dropWhile<T>(items: readonly T[], predicate: Predicate<T>): T[];
export declare function _dropRightWhile<T>(items: readonly T[], predicate: Predicate<T>): T[];
/**
 * Returns true if the _count >= limit.
 * _count counts how many times the Predicate returns true, and stops
 * when it reaches the limit.
 */
export declare function _countAtLeast<T>(items: Iterable<T>, predicate: AbortablePredicate<T>, limit: number): boolean;
/**
 * Returns true if the _count <> limit.
 * _count counts how many times the Predicate returns true, and stops
 * when it reaches the limit.
 */
export declare function _countLessThan<T>(items: Iterable<T>, predicate: AbortablePredicate<T>, limit: number): boolean;
/**
 * Counts how many items match the predicate.
 *
 * `limit` allows to exit early when limit count is reached, skipping further iterations (perf optimization).
 */
export declare function _count<T>(items: Iterable<T>, predicate: AbortablePredicate<T>, limit?: number): number;
export declare function _countBy<T>(items: Iterable<T>, mapper: Mapper<T, any>): StringMap<number>;
/**
 * Returns an intersection between 2 arrays.
 *
 * Intersecion means an array of items that are present in both of the arrays.
 *
 * It's more performant to pass a Set as a second argument.
 *
 * @example
 * _intersection([2, 1], [2, 3])
 * // [2]
 */
export declare function _intersection<T>(a1: T[], a2: T[] | Set<T>): T[];
/**
 * Returns true if there is at least 1 item common between 2 arrays.
 * Otherwise returns false.
 *
 * It's more performant to use that versus `_intersection(a1, a2).length > 0`.
 *
 * Passing second array as Set is more performant (it'll skip turning the array into Set in-place).
 */
export declare function _intersectsWith<T>(a1: T[], a2: T[] | Set<T>): boolean;
/**
 * Returns array1 minus array2.
 *
 * @example
 * _difference([2, 1], [2, 3])
 * // [1]
 *
 * Passing second array as Set is more performant (it'll skip turning the array into Set in-place).
 */
export declare function _difference<T>(a1: T[], a2: T[] | Set<T>): T[];
/**
 * Does NOT mutate the array, returns a filtered array instead.
 */
export declare function _arrayRemove<T>(a: T[], itemToRemove: T): T[];
/**
 * "Toggles" an item to be present or absent in the array,
 * based on the predicate. Respects uniqueness.
 *
 * If predicate==false - item gets removed from the array.
 * If predicate==true - item gets pushed to the array (unless it was already present).
 *
 * Pushing the item DOES MUTATE the array, same if you would do array.push manually.
 */
export declare function _arrayPushOrRemove<T>(a: T[], item: T, predicate: boolean): T[];
/**
 * Returns the sum of items, or 0 for empty array.
 */
export declare function _sum<N extends number>(items: Iterable<N>): N;
export declare function _sumBy<T, N extends number>(items: Iterable<T>, mapper: Mapper<T, N | undefined>): N;
/**
 * Map an array of T to a StringMap<V>,
 * by returning a tuple of [key, value] from a mapper function.
 * Return undefined/null/false/0/void to filter out (not include) a value.
 *
 * @example
 *
 * _mapToObject([1, 2, 3], n => [n, n * 2])
 * // { '1': 2, '2': 4, '3': 6 }
 *
 * _mapToObject([1, 2, 3], n => [n, `id${n}`])
 * // { '1': 'id1, '2': 'id2', '3': 'id3' }
 */
export declare function _mapToObject<T, V>(array: Iterable<T>, mapper: (item: T) => [key: any, value: V] | FalsyValue): StringMap<V>;
/**
 * Randomly shuffle an array values.
 * Fisher–Yates algorithm.
 * Based on: https://stackoverflow.com/a/12646864/4919972
 */
export declare function _shuffle<T>(array: T[], opt?: MutateOptions): T[];
export declare function _firstLast<T>(array: readonly T[]): [first: T, last: T];
export declare function _firstLastOrUndefined<T>(array: readonly T[]): [first: T, last: T] | undefined;
/**
 * Returns last item of non-empty array.
 * Throws if array is empty.
 */
export declare function _last<T>(array: readonly T[]): T;
/**
 * Returns last item of the array (or undefined if array is empty).
 */
export declare function _lastOrUndefined<T>(array: readonly T[]): T | undefined;
/**
 * Returns the first item of non-empty array.
 * Throws if array is empty.
 */
export declare function _first<T>(array: readonly T[]): T;
/**
 * Returns first item of the array (or undefined if array is empty).
 */
export declare function _firstOrUndefined<T>(array: readonly T[]): T | undefined;
/**
 * Returns the first item of a non-empty iterable (Set, Map.values(), generator, etc.).
 * Throws if the iterable is empty.
 *
 * Avoids the `Array.from(iter)[0]` pattern that materialises the entire iterable.
 * `for...of` with an early return advances the iterator exactly once; if the
 * iterator implements `return()` (generators, etc.), it is invoked for cleanup.
 */
export declare function _firstFromIterable<T>(iter: Iterable<T>): T;
/**
 * Returns the first item of an iterable (or undefined if the iterable is empty).
 * See `_firstFromIterable` for the iteration semantics.
 */
export declare function _firstOrUndefinedFromIterable<T>(iter: Iterable<T>): T | undefined;
export declare function _minOrUndefined<T>(array: readonly T[]): NonNullable<T> | undefined;
/**
 * Filters out nullish values (undefined and null).
 */
export declare function _min<T>(array: readonly T[]): NonNullable<T>;
export declare function _maxOrUndefined<T>(array: readonly T[]): NonNullable<T> | undefined;
/**
 * Filters out nullish values (undefined and null).
 */
export declare function _max<T>(array: readonly T[]): NonNullable<T>;
export declare function _maxBy<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T;
export declare function _minBy<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T;
export declare function _minMax<T>(array: readonly T[]): [min: NonNullable<T>, max: NonNullable<T>];
export declare function _minMaxOrUndefined<T>(array: readonly T[]): [min: NonNullable<T>, max: NonNullable<T>] | undefined;
export declare function _minMaxBy<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): [min: NonNullable<T>, max: NonNullable<T>];
export declare function _minMaxByOrUndefined<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): [min: NonNullable<T>, max: NonNullable<T>] | undefined;
export declare function _maxByOrUndefined<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T | undefined;
export declare function _minByOrUndefined<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T | undefined;
export declare function _zip<T1, T2>(array1: readonly T1[], array2: readonly T2[]): [T1, T2][];
