UNPKG

super-utils-plus

Version:

A superior alternative to Lodash with improved performance, TypeScript support, and developer experience

232 lines (231 loc) 6.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.zip = zip; exports.unzip = unzip; exports.unzipWith = unzipWith; exports.zipObject = zipObject; exports.zipObjectDeep = zipObjectDeep; exports.zipWith = zipWith; const is_1 = require("../utils/is"); /** * Creates an array of grouped elements, the first of which contains the * first elements of the given arrays, the second of which contains the * second elements of the given arrays, and so on. * * @param arrays - The arrays to process * @returns The new array of grouped elements * * @example * ```ts * zip(['a', 'b'], [1, 2], [true, false]); * // => [['a', 1, true], ['b', 2, false]] * ``` */ function zip(...arrays) { if (!arrays.length) { return []; } // Find the length of the longest array const maxLength = Math.max(...arrays.map(arr => arr ? arr.length : 0)); const result = []; // For each position, create an array of elements at that position for (let i = 0; i < maxLength; i++) { result.push(arrays.map(arr => arr[i])); } return result; } /** * This method is like zip except that it accepts an array of grouped * elements and creates an array regrouping the elements to their pre-zip * configuration. * * @param array - The array of grouped elements to process * @returns The new array of regrouped elements * * @example * ```ts * const zipped = zip(['a', 'b'], [1, 2], [true, false]); * // => [['a', 1, true], ['b', 2, false]] * * unzip(zipped); * // => [['a', 'b'], [1, 2], [true, false]] * ``` */ function unzip(array) { if (!array || !array.length) { return []; } // Use zip with spread array return zip(...array); } /** * This method is like unzip except that it accepts an iteratee to specify * how regrouped values should be combined. The iteratee is invoked with four * arguments: (accumulator, value, index, group). * * @param array - The array of grouped elements to process * @param iteratee - The function to combine regrouped values * @returns The new array of regrouped elements * * @example * ```ts * const zipped = zip([1, 2], [10, 20], [100, 200]); * // => [[1, 10, 100], [2, 20, 200]] * * unzipWith(zipped, _.add); * // => [3, 30, 300] * ``` */ function unzipWith(array, iteratee) { if (!array || !array.length) { return []; } // First unzip the array const results = unzip(array); // Then apply the iteratee to each group return results.map(group => iteratee(...group)); } /** * Creates an object composed from arrays of property names and values. * * @param props - The property identifiers * @param values - The property values * @returns The new object * * @example * ```ts * zipObject(['a', 'b'], [1, 2]); * // => { 'a': 1, 'b': 2 } * ``` */ function zipObject(props, values) { if (!props || !props.length || !values) { return {}; } const result = {}; for (let i = 0; i < props.length; i++) { if (i < values.length) { result[props[i]] = values[i]; } } return result; } /** * This method is like zipObject except that it supports property paths. * * @param paths - The property paths * @param values - The property values * @returns The new object * * @example * ```ts * zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } * ``` */ function zipObjectDeep(paths, values) { if (!paths || !paths.length || !values) { return {}; } const result = {}; for (let i = 0; i < paths.length; i++) { if (i < values.length) { // Parse the path string const path = paths[i]; const pathParts = parsePath(path); // Set the value at the path setDeep(result, pathParts, values[i]); } } return result; } /** * This method is like zip except that it accepts an iteratee to specify * how grouped values should be combined. The iteratee is invoked with the * elements of each group. * * @param arrays - The arrays to process * @param iteratee - The function to combine grouped values * @returns The new array of grouped elements * * @example * ```ts * zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { * return a + b + c; * }); * // => [111, 222] * ``` */ function zipWith(...args) { if (args.length < 2) { return []; } // Get the iteratee function from the last argument const iteratee = args.pop(); // Zip the arrays const zipped = zip(...args); // Apply the iteratee to each group return zipped.map(group => iteratee(...group)); } /** * Helper function to parse a property path into an array of parts. */ function parsePath(path) { const parts = []; let currentPart = ''; let inBrackets = false; for (let i = 0; i < path.length; i++) { const char = path[i]; if (char === '[') { if (currentPart) { parts.push(currentPart); currentPart = ''; } inBrackets = true; } else if (char === ']') { if (/^\d+$/.test(currentPart)) { parts.push(Number(currentPart)); } else { parts.push(currentPart); } currentPart = ''; inBrackets = false; } else if (char === '.' && !inBrackets) { if (currentPart) { parts.push(currentPart); currentPart = ''; } } else { currentPart += char; } } if (currentPart) { parts.push(currentPart); } return parts; } /** * Helper function to set a value at a deep path in an object. */ function setDeep(obj, path, value) { if (!path.length) { return; } const [head, ...tail] = path; if (tail.length === 0) { obj[head] = value; return; } const nextIsNumber = typeof tail[0] === 'number'; if (!(head in obj)) { obj[head] = nextIsNumber ? [] : {}; } else if ((nextIsNumber && !(0, is_1.isArray)(obj[head])) || (!nextIsNumber && typeof obj[head] !== 'object')) { obj[head] = nextIsNumber ? [] : {}; } setDeep(obj[head], tail, value); }