import type { AbortablePredicate, FalsyValue, Mapper, Predicate, SortDirection, StringMap } from '../types';
/**
 * 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.
 * @return 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[]>;
/**
 * _sortBy([{age: 20}, {age: 10}], 'age')
 * // => [{age: 10}, {age: 20}]
 *
 * Same:
 * _sortBy([{age: 20}, {age: 10}], o => o.age)
 */
export declare function _sortBy<T>(items: T[], mapper: Mapper<T, any>, mutate?: boolean, dir?: SortDirection): T[];
/**
 * Alias for _sortBy with descending order.
 */
export declare function _sortDescBy<T>(items: T[], mapper: Mapper<T, any>, mutate?: boolean): 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[];
/**
 * 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[], mutate?: boolean): T[];
/**
 * 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;
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 _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][];
