diff --git a/benchmarks/performance/unzip.bench.ts b/benchmarks/performance/unzip.bench.ts index 2dc6cbaed..b19d49f2c 100644 --- a/benchmarks/performance/unzip.bench.ts +++ b/benchmarks/performance/unzip.bench.ts @@ -1,8 +1,10 @@ import { bench, describe } from 'vitest'; import { unzip as unzipToolkit_ } from 'es-toolkit'; +import { unzip as unzipToolkitCompat_ } from 'es-toolkit/compat'; import { unzip as unzipLodash_ } from 'lodash'; const unzipToolkit = unzipToolkit_; +const unzipToolkitCompat = unzipToolkitCompat_; const unzipLodash = unzipLodash_; describe('unzip, small arrays', () => { @@ -13,6 +15,13 @@ describe('unzip, small arrays', () => { ]); }); + bench('es-toolkit/compat/unzip', () => { + unzipToolkitCompat([ + ['a', 1, true], + ['b', 2, false], + ]); + }); + bench('lodash/unzip', () => { unzipLodash([ ['a', 1, true], @@ -28,6 +37,10 @@ describe('unzip, large arrays', () => { unzipToolkit(largeArray); }); + bench('es-toolkit/compat/unzip', () => { + unzipToolkitCompat(largeArray); + }); + bench('lodash/unzip', () => { unzipLodash(largeArray); }); diff --git a/src/compat/array/unzip.spec.ts b/src/compat/array/unzip.spec.ts new file mode 100644 index 000000000..34d46f5cd --- /dev/null +++ b/src/compat/array/unzip.spec.ts @@ -0,0 +1,75 @@ +import { describe, expect, it } from 'vitest'; +import { unzip } from './unzip'; +import { zip } from '../../array/zip'; + +describe('unzip', () => { + const object = { + 'an empty array': [[], []], + '2-tuples': [ + [ + ['barney', 'fred'], + [36, 40], + ], + [ + ['barney', 36], + ['fred', 40], + ], + ], + '3-tuples': [ + [ + ['barney', 'fred'], + [36, 40], + [false, true], + ], + [ + ['barney', 36, false], + ['fred', 40, true], + ], + ], + }; + + Object.entries(object).forEach(([key, pair]) => { + it(`\`_.unzip\` should work with ${key}`, () => { + const actual = unzip(pair[1]); + expect(actual).toEqual(pair[0]); + }); + }); + + it(`\`_.unzip\` should work with tuples of different lengths`, () => { + const pair = [ + [ + ['barney', 36], + ['fred', 40, false], + ], + [ + ['barney', 'fred'], + [36, 40], + [undefined, false], + ], + ]; + const actual = unzip(pair[1]) as any; + expect('2' in actual[0]).toBeTruthy(); + expect(actual).toEqual([ + ['barney', 36, undefined], + ['fred', 40, false], + ]); + }); + + it(`\`_.unzip\` should support consuming its return value`, () => { + const expected = [ + ['barney', 'fred'], + [36, 40], + ]; + // @ts-expect-error - TS doesn't support array types in rest parameters + expect(unzip(zip(...unzip(zip(...expected))))).toEqual(expected); + }); + + it(`\`_.unzip\` should work with array-like object`, () => { + const array = { 0: { 0: 'a', 1: 1, length: 2 }, 1: { 0: 'b', 1: 2, length: 2 }, length: 2 }; + const actual = unzip(array); + expect(actual).toEqual([ + ['a', 'b'], + [1, 2], + ]); + }); +}); diff --git a/src/compat/array/unzip.ts b/src/compat/array/unzip.ts new file mode 100644 index 000000000..7e8911066 --- /dev/null +++ b/src/compat/array/unzip.ts @@ -0,0 +1,25 @@ +import { unzip as unzipToolkit } from '../../array/unzip.ts'; +import { isArrayLikeObject } from '../predicate/isArrayLikeObject.ts'; + +/** + * Gathers elements in the same position in an internal array + * from a grouped array of elements and returns them as a new array. + * + * @template T - The type of elements in the nested array. + * @param {T[][] | ArrayLike> | null | undefined} array - The nested array to unzip. + * @returns {T[][]} A new array of unzipped elements. + * + * @example + * const zipped = [['a', true, 1],['b', false, 2]]; + * const result = unzip(zipped); + * // result will be [['a', 'b'], [true, false], [1, 2]] + */ +export function unzip(array: T[][] | ArrayLike> | null | undefined): T[][] { + if (!isArrayLikeObject(array) || !array.length) { + return []; + } + if (Array.isArray(array)) { + return unzipToolkit(array); + } + return unzipToolkit(Array.from(array, value => Array.from(value))); +} diff --git a/src/compat/index.ts b/src/compat/index.ts index 8e388910c..e0db47655 100644 --- a/src/compat/index.ts +++ b/src/compat/index.ts @@ -61,6 +61,7 @@ export { tail } from './array/tail.ts'; export { take } from './array/take.ts'; export { takeRight } from './array/takeRight.ts'; export { uniq } from './array/uniq.ts'; +export { unzip } from './array/unzip.ts'; export { without } from './array/without.ts'; export { zipObjectDeep } from './array/zipObjectDeep.ts';