mirror of
https://github.com/toss/es-toolkit.git
synced 2024-11-27 14:57:44 +03:00
feat(flatMapDeep): Add flatMapDeep (#464)
* feat: add flatMapDeep new function * refac: flatMapDeep refactor * fix: benchmark fix * fix: benchmark fix * Apply suggestions from code review --------- Co-authored-by: Sojin Park <raon0211@gmail.com> Co-authored-by: Sojin Park <raon0211@toss.im>
This commit is contained in:
parent
cb33fd2242
commit
7ad4ef15d3
29
benchmarks/performance/flatMapDeep.bench.ts
Normal file
29
benchmarks/performance/flatMapDeep.bench.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { bench, describe } from 'vitest';
|
||||||
|
import { flatMapDeep as flatMapDeepToolkit } from 'es-toolkit';
|
||||||
|
import { flatMapDeep as flatMapDeepLodash } from 'lodash';
|
||||||
|
|
||||||
|
function createNestedArray(arr: any[], depth: number) {
|
||||||
|
let result = arr;
|
||||||
|
|
||||||
|
for (let i = 0; i < depth; i++) {
|
||||||
|
result = [result];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('flatMapDeep', () => {
|
||||||
|
const iterateeDepth = (item: number) => createNestedArray([item, item, item], 10);
|
||||||
|
const arr = Array.from({ length: 30 }, (_, i) => i);
|
||||||
|
|
||||||
|
bench('es-toolkit/flatMapDeep', () => {
|
||||||
|
flatMapDeepToolkit(arr, iterateeDepth);
|
||||||
|
});
|
||||||
|
|
||||||
|
bench('lodash/flatMapDeep', () => {
|
||||||
|
flatMapDeepLodash(arr, iterateeDepth);
|
||||||
|
});
|
||||||
|
|
||||||
|
bench('js built-in/map.flat', () => {
|
||||||
|
arr.map(iterateeDepth).flat(Infinity);
|
||||||
|
});
|
||||||
|
});
|
@ -66,6 +66,7 @@ function sidebar(): DefaultTheme.Sidebar {
|
|||||||
{ text: 'find (compat)', link: '/reference/compat/array/find' },
|
{ text: 'find (compat)', link: '/reference/compat/array/find' },
|
||||||
{ text: 'findIndex (compat)', link: '/reference/compat/array/findIndex' },
|
{ text: 'findIndex (compat)', link: '/reference/compat/array/findIndex' },
|
||||||
{ text: 'flatMap', link: '/reference/array/flatMap' },
|
{ text: 'flatMap', link: '/reference/array/flatMap' },
|
||||||
|
{ text: 'flatMapDeep', link: '/reference/array/flatMapDeep' },
|
||||||
{ text: 'flatten', link: '/reference/array/flatten' },
|
{ text: 'flatten', link: '/reference/array/flatten' },
|
||||||
{ text: 'flattenDeep', link: '/reference/array/flattenDeep' },
|
{ text: 'flattenDeep', link: '/reference/array/flattenDeep' },
|
||||||
{ text: 'forEachRight', link: '/reference/array/forEachRight' },
|
{ text: 'forEachRight', link: '/reference/array/forEachRight' },
|
||||||
|
@ -71,6 +71,7 @@ function sidebar(): DefaultTheme.Sidebar {
|
|||||||
{ text: 'find (호환성)', link: '/ko/reference/compat/array/find' },
|
{ text: 'find (호환성)', link: '/ko/reference/compat/array/find' },
|
||||||
{ text: 'findIndex (호환성)', link: '/ko/reference/compat/array/findIndex' },
|
{ text: 'findIndex (호환성)', link: '/ko/reference/compat/array/findIndex' },
|
||||||
{ text: 'flatMap', link: '/ko/reference/array/flatMap' },
|
{ text: 'flatMap', link: '/ko/reference/array/flatMap' },
|
||||||
|
{ text: 'flatMapDeep', link: '/ko/reference/array/flatMapDeep' },
|
||||||
{ text: 'flatten', link: '/ko/reference/array/flatten' },
|
{ text: 'flatten', link: '/ko/reference/array/flatten' },
|
||||||
{ text: 'flattenDeep', link: '/ko/reference/array/flattenDeep' },
|
{ text: 'flattenDeep', link: '/ko/reference/array/flattenDeep' },
|
||||||
{ text: 'forEachRight', link: '/ko/reference/array/forEachRight' },
|
{ text: 'forEachRight', link: '/ko/reference/array/forEachRight' },
|
||||||
|
35
docs/ko/reference/array/flatMapDeep.md
Normal file
35
docs/ko/reference/array/flatMapDeep.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# flatMapDeep
|
||||||
|
|
||||||
|
중첩된 배열의 각 요소를 주어진 iteratee 함수로 매핑 후, 모든 깊이를 풀어서 평탄화해요.
|
||||||
|
|
||||||
|
JavaScript 언어에 포함된 [Array#flat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat)을 [Array#map](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map)과 함께 `map(iteratee).flat(Infinity)`으로 호출했을 때와 동일하게 동작하지만, 더 빨라요.
|
||||||
|
|
||||||
|
## 인터페이스
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function flattenDeep<T>(arr: T[]): Array<ExtractNestedArrayType<T>>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 파라미터
|
||||||
|
|
||||||
|
- `arr` (`T[]`): 평탄화할 중첩 배열이에요.
|
||||||
|
- `iteratee` (`T[]`): 각 배열 요소를 매핑하는 함수에요.
|
||||||
|
|
||||||
|
### 반환 값
|
||||||
|
|
||||||
|
(`Array<ExtractNestedArrayType<T>>`): 각 요소가 매핑되고, 모든 깊이가 평탄해진 새로운 배열이에요.
|
||||||
|
|
||||||
|
## 예시
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const array = [1, 2, 3];
|
||||||
|
|
||||||
|
const result1 = flatMapDeep(array, item => [item, item]);
|
||||||
|
// [1, 1, 2, 2, 3, 3]를 반환해요.
|
||||||
|
|
||||||
|
const result2 = flatMapDeep(array, item => [[item, item]]);
|
||||||
|
// [1, 1, 2, 2, 3, 3]를 반환해요.
|
||||||
|
|
||||||
|
const result3 = flatMapDeep(array, item => [[[item, item]]]);
|
||||||
|
// [1, 1, 2, 2, 3, 3]를 반환해요.
|
||||||
|
```
|
35
docs/reference/array/flatMapDeep.md
Normal file
35
docs/reference/array/flatMapDeep.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# flatMapDeep
|
||||||
|
|
||||||
|
Map each element of a nested array to the given iteratee function, then unpack and flatten all depths.
|
||||||
|
|
||||||
|
It works the same as if you called [Array#flat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) with [Array#map](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map) as `map(iteratee).flat(Infinity)` in the JavaScript language, but it's faster.
|
||||||
|
|
||||||
|
## Signature
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function flattenDeep<T>(arr: T[]): Array<ExtractNestedArrayType<T>>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
- `arr` (`T[]`): The array to flatten.
|
||||||
|
- `iteratee` (`T[]`): A function that maps each array element.
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
(`Array<ExtractNestedArrayType<T>>`): A new array with each element mapped and all depths flattened.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const array = [1, 2, 3];
|
||||||
|
|
||||||
|
const result1 = flatMapDeep(array, item => [item, item]);
|
||||||
|
// Return [1, 1, 2, 2, 3, 3]
|
||||||
|
|
||||||
|
const result2 = flatMapDeep(array, item => [[item, item]]);
|
||||||
|
// Return [1, 1, 2, 2, 3, 3]
|
||||||
|
|
||||||
|
const result3 = flatMapDeep(array, item => [[[item, item]]]);
|
||||||
|
// Return [1, 1, 2, 2, 3, 3]
|
||||||
|
```
|
@ -166,4 +166,4 @@
|
|||||||
"lint": "eslint --config eslint.config.mjs",
|
"lint": "eslint --config eslint.config.mjs",
|
||||||
"format": "prettier --write ."
|
"format": "prettier --write ."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
src/array/flatMapDeep.spec.ts
Normal file
20
src/array/flatMapDeep.spec.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { flatMapDeep } from './flatMapDeep';
|
||||||
|
|
||||||
|
describe('flatMapDeep', () => {
|
||||||
|
it('should map and deeply flatten an array', () => {
|
||||||
|
const result1 = flatMapDeep([1, 2, 3], n => [[n, n]]);
|
||||||
|
expect(result1).toEqual([1, 1, 2, 2, 3, 3]);
|
||||||
|
|
||||||
|
const result2 = flatMapDeep([1, 2, 3], n => [[[n]], [[n]]]);
|
||||||
|
expect(result2).toEqual([1, 1, 2, 2, 3, 3]);
|
||||||
|
|
||||||
|
const result3 = flatMapDeep([1, 2, 3], n => [n, [n, [n, [n]]]]);
|
||||||
|
expect(result3).toEqual([1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an empty array when provided with an empty array', () => {
|
||||||
|
const result = flatMapDeep([], n => [[n]]);
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
18
src/array/flatMapDeep.ts
Normal file
18
src/array/flatMapDeep.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { ExtractNestedArrayType, flattenDeep } from './flattenDeep';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively maps each element in an array using a provided iteratee function and then deeply flattens the resulting array.
|
||||||
|
*
|
||||||
|
* @template T - The type of elements within the array.
|
||||||
|
* @template U - The type of elements within the returned array from the iteratee function.
|
||||||
|
* @param {T[]} arr - The array to flatten.
|
||||||
|
* @param {(item: T) => U} iteratee - The function that produces the new array elements.
|
||||||
|
* @returns {Array<ExtractNestedArrayType<U>>} A new array that has been flattened.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const result = flatMapDeep([1, 2, 3], n => [[n, n]]);
|
||||||
|
* // [1, 1, 2, 2, 3, 3]
|
||||||
|
*/
|
||||||
|
export function flatMapDeep<T, U>(arr: readonly T[], iteratee: (item: T) => U): Array<ExtractNestedArrayType<U>> {
|
||||||
|
return flattenDeep(arr.map((item: T) => iteratee(item)));
|
||||||
|
}
|
@ -10,7 +10,7 @@ import { flatten } from './flatten.ts';
|
|||||||
* ExtractNestedArrayType<(boolean | (string | number[])[])[]>
|
* ExtractNestedArrayType<(boolean | (string | number[])[])[]>
|
||||||
* // string | number | boolean
|
* // string | number | boolean
|
||||||
*/
|
*/
|
||||||
type ExtractNestedArrayType<T> = T extends ReadonlyArray<infer U> ? ExtractNestedArrayType<U> : T;
|
export type ExtractNestedArrayType<T> = T extends ReadonlyArray<infer U> ? ExtractNestedArrayType<U> : T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flattens all depths of a nested array.
|
* Flattens all depths of a nested array.
|
||||||
|
@ -11,6 +11,7 @@ export { dropRightWhile } from './dropRightWhile.ts';
|
|||||||
export { dropWhile } from './dropWhile.ts';
|
export { dropWhile } from './dropWhile.ts';
|
||||||
export { fill } from './fill.ts';
|
export { fill } from './fill.ts';
|
||||||
export { flatMap } from './flatMap.ts';
|
export { flatMap } from './flatMap.ts';
|
||||||
|
export { flatMapDeep } from './flatMapDeep.ts';
|
||||||
export { flatten } from './flatten.ts';
|
export { flatten } from './flatten.ts';
|
||||||
export { flattenDeep } from './flattenDeep.ts';
|
export { flattenDeep } from './flattenDeep.ts';
|
||||||
export { forEachRight } from './forEachRight.ts';
|
export { forEachRight } from './forEachRight.ts';
|
||||||
|
Loading…
Reference in New Issue
Block a user