UNPKG

ts-data-forge

Version:

[![npm version](https://img.shields.io/npm/v/ts-data-forge.svg)](https://www.npmjs.com/package/ts-data-forge) [![npm downloads](https://img.shields.io/npm/dm/ts-data-forge.svg)](https://www.npmjs.com/package/ts-data-forge) [![License](https://img.shields.

337 lines (334 loc) 10.7 kB
import '../../collections/imap-mapped.mjs'; import { IMap } from '../../collections/imap.mjs'; import '../../collections/iset-mapped.mjs'; import '../../collections/iset.mjs'; import '@sindresorhus/is'; import { castMutable } from '../../others/cast-mutable.mjs'; import { tp } from '../../others/tuple.mjs'; import '../../number/branded-types/finite-number.mjs'; import '../../number/branded-types/int.mjs'; import '../../number/branded-types/int16.mjs'; import '../../number/branded-types/int32.mjs'; import '../../number/branded-types/non-negative-finite-number.mjs'; import '../../number/branded-types/non-negative-int16.mjs'; import '../../number/branded-types/non-negative-int32.mjs'; import '../../number/branded-types/non-zero-finite-number.mjs'; import '../../number/branded-types/non-zero-int.mjs'; import '../../number/branded-types/non-zero-int16.mjs'; import '../../number/branded-types/non-zero-int32.mjs'; import '../../number/branded-types/non-zero-safe-int.mjs'; import '../../number/branded-types/non-zero-uint16.mjs'; import '../../number/branded-types/non-zero-uint32.mjs'; import '../../number/branded-types/positive-finite-number.mjs'; import '../../number/branded-types/positive-int.mjs'; import '../../number/branded-types/positive-int16.mjs'; import '../../number/branded-types/positive-int32.mjs'; import '../../number/branded-types/positive-safe-int.mjs'; import '../../number/branded-types/positive-uint16.mjs'; import { asPositiveUint32 } from '../../number/branded-types/positive-uint32.mjs'; import '../../number/branded-types/safe-int.mjs'; import '../../number/branded-types/safe-uint.mjs'; import '../../number/branded-types/uint.mjs'; import '../../number/branded-types/uint16.mjs'; import { asUint32, Uint32 } from '../../number/branded-types/uint32.mjs'; import '../../number/enum/int8.mjs'; import '../../number/enum/uint8.mjs'; import '../../number/num.mjs'; import '../../number/refined-number-utils.mjs'; import { seq, newArray } from './array-utils-creation.mjs'; import { size } from './array-utils-size.mjs'; function map(...args) { switch (args.length) { case 2: { const [array, mapFn] = args; // eslint-disable-next-line total-functions/no-unsafe-type-assertion return array.map(mapFn); } case 1: { const [mapFn] = args; return (array) => map(array, mapFn); } } } function scan(...args) { switch (args.length) { case 3: { const [array, reducer, init] = args; const mut_result = castMutable(newArray(asPositiveUint32(array.length + 1), init)); let mut_acc = init; for (const [index, value] of array.entries()) { mut_acc = reducer(mut_acc, value, asUint32(index)); mut_result[index + 1] = mut_acc; } return mut_result; } case 2: { const [reducer, init] = args; return (array) => scan(array, reducer, init); } } } /** * Reverses an array. * * @example * * ```ts * const tuple = [1, 'two', true] as const; * * const reversed = Arr.toReversed(tuple); * * const expected = [true, 'two', 1] as const; * * assert.deepStrictEqual(reversed, expected); * ``` */ const toReversed = (array) => // eslint-disable-next-line total-functions/no-unsafe-type-assertion array.toReversed(); /** * Sorts an array. * * @example * * ```ts * const numbers = [3, 1, 2] as const; * * const words = ['banana', 'apple', 'cherry'] as const; * * const ascendingNumbers = Arr.toSorted(numbers); * * const alphabetical = Arr.toSorted(words, (left, right) => * left.localeCompare(right), * ); * * const expectedNumbers = [1, 2, 3] as const; * * const expectedWords = ['apple', 'banana', 'cherry'] as const; * * assert.deepStrictEqual(ascendingNumbers, expectedNumbers); * * assert.deepStrictEqual(alphabetical, expectedWords); * ``` */ const toSorted = (...[array, comparator]) => // eslint-disable-next-line total-functions/no-unsafe-type-assertion array.toSorted( // eslint-disable-next-line total-functions/no-unsafe-type-assertion comparator ?? // eslint-disable-next-line total-functions/no-unsafe-type-assertion ((x, y) => x - y)); function toSortedBy(array, comparatorValueMapper, comparator) { return array.toSorted((x, y) => comparator === undefined ? // This branch assumes V is number if comparator is undefined. // The overloads should handle this, but explicit cast might be needed if V is not number. // eslint-disable-next-line total-functions/no-unsafe-type-assertion comparatorValueMapper(x) - // eslint-disable-next-line total-functions/no-unsafe-type-assertion comparatorValueMapper(y) : comparator(comparatorValueMapper(x), comparatorValueMapper(y))); } function filter(...args) { switch (args.length) { case 2: { const [array, predicate] = args; return array.filter((a, i) => predicate(a, asUint32(i))); } case 1: { const [predicate] = args; return (array) => filter(array, predicate); } } } function filterNot(...args) { switch (args.length) { case 2: { const [array, predicate] = args; return array.filter((a, i) => !predicate(a, asUint32(i))); } case 1: { const [predicate] = args; return (array) => filterNot(array, predicate); } } } /** * Creates a new array with unique elements. * * @example * * ```ts * const letters = ['a', 'b', 'a', 'c', 'b'] as const; * * const uniqueLetters = Arr.uniq(letters); * * const expected = ['a', 'b', 'c'] as const; * * assert.deepStrictEqual(uniqueLetters, expected); * ``` */ const uniq = (array) => // eslint-disable-next-line total-functions/no-unsafe-type-assertion Array.from(new Set(array)); /** * Creates a new array with unique elements based on a mapped value. * * @example * * ```ts * const people = [ * { id: 1, name: 'Ada' }, * { id: 2, name: 'Brian' }, * { id: 1, name: 'Alan' }, * { id: 3, name: 'Grace' }, * ] as const; * * const uniqueById = Arr.uniqBy(people, (person) => person.id); * * const expected = [ * { id: 1, name: 'Ada' }, * { id: 2, name: 'Brian' }, * { id: 3, name: 'Grace' }, * ] as const; * * assert.deepStrictEqual(uniqueById, expected); * ``` */ const uniqBy = (array, mapFn) => { const mut_mappedValues = new Set(); // eslint-disable-next-line total-functions/no-unsafe-type-assertion return array.filter((val) => { const mappedValue = mapFn(val); if (mut_mappedValues.has(mappedValue)) return false; mut_mappedValues.add(mappedValue); return true; }); }; function flat(...args) { switch (args.length) { case 2: { const [array, depth] = args; return array.flat(depth); } case 1: { const [arrayOrDepth] = args; if (typeof arrayOrDepth === 'number') { const depth = arrayOrDepth; return (array) => flat(array, depth); } else if (arrayOrDepth === undefined) { return (array) => flat(array, 1); } else { return arrayOrDepth.flat(); } } case 0: return (array) => flat(array, 1); } } function flatMap(...args) { switch (args.length) { case 2: { const [array, mapFn] = args; return array.flatMap((a, i) => mapFn(a, asUint32(i))); } case 1: { const [mapFn] = args; return (array) => flatMap(array, mapFn); } } } function partition(...args) { switch (args.length) { case 2: { const [array, chunkSize] = args; return chunkSize < 2 ? [] : // eslint-disable-next-line total-functions/no-partial-division seq(asUint32(Math.ceil(array.length / chunkSize))).map((i) => array.slice(chunkSize * i, chunkSize * (i + 1))); } case 1: { const [chunkSize] = args; return (array) => partition(array, chunkSize); } } } /** * Concatenates two arrays. * * @example * * ```ts * const numbers = [1, 2] as const; * * const words = ['three', 'four'] as const; * * const combined = Arr.concat(numbers, words); * * const expectedCombined = [1, 2, 'three', 'four'] as const; * * assert.deepStrictEqual(combined, expectedCombined); * ``` */ const concat = (array1, array2) => [...array1, ...array2]; function groupBy(...args) { switch (args.length) { case 2: { const [array, grouper] = args; const mut_groups = new Map(); // Store mutable arrays internally for (const [index, e] of array.entries()) { const key = grouper(e, asUint32(index)); // Ensure index is treated as SizeType.Arr const mut_group = mut_groups.get(key); if (mut_group !== undefined) { mut_group.push(e); } else { mut_groups.set(key, [e]); } } // Cast to IMap<G, readonly A[]> for the public interface return IMap.create(mut_groups); } case 1: { const [grouper] = args; return (array) => groupBy(array, grouper); } } } /** * Creates an array of tuples by pairing corresponding elements from two arrays. * * @example * * ```ts * const letters = ['a', 'b', 'c'] as const; * * const numbers = [1, 2, 3] as const; * * const pairs = Arr.zip(letters, numbers); * * const expectedPairs = [ * ['a', 1], * ['b', 2], * ['c', 3], * ] as const; * * assert.deepStrictEqual(pairs, expectedPairs); * ``` */ const zip = (array1, array2) => // eslint-disable-next-line total-functions/no-unsafe-type-assertion seq(Uint32.min(size(array1), size(array2))).map((i) => // Non-null assertion is safe here because `i` is always within bounds of both arrays up to the length of the shorter one. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion tp(array1[i], array2[i])); /** * Alias for `partition`. * * @see {@link partition} */ const chunk = partition; export { chunk, concat, filter, filterNot, flat, flatMap, groupBy, map, partition, scan, toReversed, toSorted, toSortedBy, uniq, uniqBy, zip }; //# sourceMappingURL=array-utils-transformation.mjs.map