mirror of
https://github.com/toss/es-toolkit.git
synced 2024-11-24 11:45:26 +03:00
feat(flatten): add compatibility with lodash (#330)
* feat(flatten): add compatibility * Add bench * Add doc * fix jsdoc
This commit is contained in:
parent
25217a571e
commit
2d1c406398
@ -1,5 +1,6 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { flatten as flattenToolkit } from 'es-toolkit';
|
||||
import { flatten as flattenCompatToolkit } from 'es-toolkit/compat';
|
||||
import { flattenDepth as flattenDepthLodash } from 'lodash';
|
||||
|
||||
const createNestedArray = (values: any[]) => {
|
||||
@ -17,6 +18,10 @@ describe('flatten', () => {
|
||||
flattenToolkit(arr, 30);
|
||||
});
|
||||
|
||||
bench('es-toolkit/flatten (compat)', () => {
|
||||
flattenCompatToolkit(arr, 30);
|
||||
});
|
||||
|
||||
bench('lodash/flattenDepth', () => {
|
||||
flattenDepthLodash(arr, 30);
|
||||
});
|
||||
|
@ -64,7 +64,7 @@ Even if a feature is marked "in review," it might already be under review to ens
|
||||
| [fill](https://lodash.com/docs/4.17.15#fill) | ✅ |
|
||||
| [findIndex](https://lodash.com/docs/4.17.15#findIndex) | ❌ |
|
||||
| [findLastIndex](https://lodash.com/docs/4.17.15#findIndex) | ❌ |
|
||||
| [flatten](https://lodash.com/docs/4.17.15#flatten) | 📝 |
|
||||
| [flatten](https://lodash.com/docs/4.17.15#flatten) | ✅ |
|
||||
| [flattenDeep](https://lodash.com/docs/4.17.15#flattenDeep) | 📝 |
|
||||
| [flattenDepth](https://lodash.com/docs/4.17.15#flattenDepth) | 📝 |
|
||||
| [fromPairs](https://lodash.com/docs/4.17.15#fromPairs) | ❌ |
|
||||
|
@ -65,7 +65,7 @@ chunk([1, 2, 3, 4], 0);
|
||||
| [fill](https://lodash.com/docs/4.17.15#fill) | ✅ |
|
||||
| [findIndex](https://lodash.com/docs/4.17.15#findIndex) | ❌ |
|
||||
| [findLastIndex](https://lodash.com/docs/4.17.15#findIndex) | ❌ |
|
||||
| [flatten](https://lodash.com/docs/4.17.15#flatten) | 📝 |
|
||||
| [flatten](https://lodash.com/docs/4.17.15#flatten) | ✅ |
|
||||
| [flattenDeep](https://lodash.com/docs/4.17.15#flattenDeep) | 📝 |
|
||||
| [flattenDepth](https://lodash.com/docs/4.17.15#flattenDepth) | 📝 |
|
||||
| [fromPairs](https://lodash.com/docs/4.17.15#fromPairs) | ❌ |
|
||||
|
@ -64,7 +64,7 @@ chunk([1, 2, 3, 4], 0);
|
||||
| [fill](https://lodash.com/docs/4.17.15#fill) | ✅ |
|
||||
| [findIndex](https://lodash.com/docs/4.17.15#findIndex) | ❌ |
|
||||
| [findLastIndex](https://lodash.com/docs/4.17.15#findIndex) | ❌ |
|
||||
| [flatten](https://lodash.com/docs/4.17.15#flatten) | 📝 |
|
||||
| [flatten](https://lodash.com/docs/4.17.15#flatten) | ✅ |
|
||||
| [flattenDeep](https://lodash.com/docs/4.17.15#flattenDeep) | 📝 |
|
||||
| [flattenDepth](https://lodash.com/docs/4.17.15#flattenDepth) | 📝 |
|
||||
| [fromPairs](https://lodash.com/docs/4.17.15#fromPairs) | ❌ |
|
||||
|
54
src/compat/array/flatten.spec.ts
Normal file
54
src/compat/array/flatten.spec.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { flatten } from './flatten';
|
||||
import { args } from '../_internal/args';
|
||||
|
||||
describe('flatten', () => {
|
||||
it('should flatten `arguments` objects', () => {
|
||||
const array = [args, [args]];
|
||||
const expected = [1, 2, 3, args];
|
||||
const actual = flatten(array);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should treat sparse arrays as dense', () => {
|
||||
const array = [[1, 2, 3], Array(3)];
|
||||
const expected = [1, 2, 3, undefined, undefined, undefined];
|
||||
const actual = flatten(array);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
expect('4' in actual).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should flatten objects with a truthy `Symbol.isConcatSpreadable` value', () => {
|
||||
const object = { 0: 'a', length: 1, [Symbol.isConcatSpreadable]: true };
|
||||
const array = [object];
|
||||
const expected = ['a'];
|
||||
const actual = flatten(array);
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should work with empty arrays', () => {
|
||||
const array = [[], [[]], [[], [[[]]]]];
|
||||
const expected = [[], [], [[[]]]];
|
||||
const actual = flatten(array);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should support flattening of nested arrays', () => {
|
||||
const array = [1, [2, [3, [4]], 5]];
|
||||
const expected = [1, 2, [3, [4]], 5];
|
||||
const actual = flatten(array);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return an empty array for non array-like objects', () => {
|
||||
const nonArray = { 0: 'a' };
|
||||
const expected: [] = [];
|
||||
const actual = flatten(nonArray);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
47
src/compat/array/flatten.ts
Normal file
47
src/compat/array/flatten.ts
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Flattens an array up to the specified depth.
|
||||
*
|
||||
* @template T - The type of elements within the array.
|
||||
* @template D - The depth to which the array should be flattened.
|
||||
* @param {T[] | object} value - The object to flatten.
|
||||
* @param {D} depth - The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.
|
||||
* @returns {Array<FlatArray<T[], D>> | []} A new array that has been flattened.
|
||||
*
|
||||
* @example
|
||||
* const arr = flatten([1, [2, 3], [4, [5, 6]]], 1);
|
||||
* // Returns: [1, 2, 3, 4, [5, 6]]
|
||||
*
|
||||
* const arr = flatten([1, [2, 3], [4, [5, 6]]], 2);
|
||||
* // Returns: [1, 2, 3, 4, 5, 6]
|
||||
*/
|
||||
export function flatten<T, D extends number = 1>(value: T[] | object, depth = 1 as D): Array<FlatArray<T[], D>> | [] {
|
||||
const result: Array<FlatArray<T[], D>> = [];
|
||||
const flooredDepth = Math.floor(depth);
|
||||
|
||||
if (!Array.isArray(value)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const recursive = (arr: T[], currentDepth: number) => {
|
||||
for (const item of arr) {
|
||||
if (
|
||||
currentDepth < flooredDepth &&
|
||||
(Array.isArray(item) ||
|
||||
Boolean(item?.[Symbol.isConcatSpreadable as keyof object]) ||
|
||||
(item !== null && typeof item === 'object' && Object.prototype.toString.call(item) === '[object Arguments]'))
|
||||
) {
|
||||
if (Array.isArray(item)) {
|
||||
recursive(item, currentDepth + 1);
|
||||
} else {
|
||||
recursive(Array.from(item as T[]), currentDepth + 1);
|
||||
}
|
||||
} else {
|
||||
result.push(item as FlatArray<T[], D>);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
recursive(value, 0);
|
||||
|
||||
return result;
|
||||
}
|
@ -28,6 +28,7 @@ export { chunk } from './array/chunk.ts';
|
||||
export { concat } from './array/concat.ts';
|
||||
export { difference } from './array/difference.ts';
|
||||
export { fill } from './array/fill.ts';
|
||||
export { flatten } from './array/flatten.ts';
|
||||
export { zipObjectDeep } from './array/zipObjectDeep.ts';
|
||||
export { head as first } from '../index.ts';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user