feat(flatMap): add flatMap function (#209)

* feat(flatMap): add flatMap function

* docs: fix docs

* Update src/array/flatMap.ts

---------

Co-authored-by: Sojin Park <raon0211@gmail.com>
This commit is contained in:
Gromit (전민재) 2024-07-15 22:43:15 +09:00 committed by GitHub
parent 6a43cebe4f
commit fec678cf34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 177 additions and 0 deletions

View File

@ -0,0 +1,29 @@
import { bench, describe } from 'vitest';
import { flatMap as flatMapToolkit } from 'es-toolkit';
import { flatMapDepth as flatMapDepthLodash } from 'lodash';
function createNestedArray(arr: any[], depth: number) {
let result = arr;
for (let i = 0; i < depth; i++) {
result = [result];
}
return result;
}
describe('flatMap', () => {
const iterateeDepth = (item: number) => createNestedArray([item, item, item], 10);
const arr = Array.from({ length: 30 }, (_, i) => i);
bench('es-toolkit/flatMap', () => {
flatMapToolkit(arr, iterateeDepth, 10);
});
bench('lodash/flatMapDepth', () => {
flatMapDepthLodash(arr, iterateeDepth, 10);
});
bench('js built-in/map.flat', () => {
arr.map(iterateeDepth).flat(10);
});
});

View File

@ -60,6 +60,7 @@ function sidebar(): DefaultTheme.Sidebar {
{ text: 'dropRightWhile', link: '/reference/array/dropRightWhile' },
{ text: 'fill', link: '/reference/array/fill' },
{ text: 'toFilled', link: '/reference/array/toFilled' },
{ text: 'flatMap', link: '/reference/array/flatMap' },
{ text: 'flatten', link: '/reference/array/flatten' },
{ text: 'flattenDeep', link: '/reference/array/flattenDeep' },
{ text: 'forEachRight', link: '/reference/array/forEachRight' },

View File

@ -65,6 +65,7 @@ function sidebar(): DefaultTheme.Sidebar {
},
{ text: 'fill', link: '/ko/reference/array/fill' },
{ text: 'toFilled', link: '/ko/reference/array/toFilled' },
{ text: 'flatMap', link: '/ko/reference/array/flatMap' },
{ text: 'flatten', link: '/ko/reference/array/flatten' },
{ text: 'flattenDeep', link: '/ko/reference/array/flattenDeep' },
{ text: 'forEachRight', link: '/reference/array/forEachRight' },

View File

@ -0,0 +1,40 @@
# flatMap
중첩된 배열의 각 요소를 주어진 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(depth)`으로 호출했을 때와 동일하게 동작하지만, 더 빨라요.
## 인터페이스
```typescript
function flatMap<T, U, D extends number = 1>(
arr: readonly T[],
iteratee: (item: T) => U,
depth?: D
): Array<FlatArray<U[], D>>;
```
### 파라미터
- `arr` (`T[]`): 평탄화할 중첩 배열이에요.
- `iteratee` (`T[]`): 각 배열 요소를 매핑하는 함수에요.
- `depth` (`D`): 평탄화할 깊이에요. 기본값은 1이에요.
### 반환 값
(`Array<FlatArray<U[], D>>`): 각 요소가 매핑되고, 원하는 깊이까지 평탄해진 새로운 배열이에요.
## 예시
```typescript
const array = [1, 2, 3];
const result1 = flatMap(array, item => [item, item], 1);
// [1, 1, 2, 2, 3, 3]를 반환해요.
const result2 = flatMap(array, item => [[item, item]], 2);
// [1, 1, 2, 2, 3, 3]를 반환해요.
const result3 = flatMap(array, item => [[[item, item]]], 3);
// [1, 1, 2, 2, 3, 3]를 반환해요.
```

View File

@ -0,0 +1,40 @@
# flatMap
Map each element of a nested array to a given iteratee function, then flatten it to the desired depth.
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(depth)` in the JavaScript language, but it's faster.
## Signature
```typescript
function flatMap<T, U, D extends number = 1>(
arr: readonly T[],
iteratee: (item: T) => U,
depth?: D
): Array<FlatArray<U[], D>>;
```
### Parameters
- `arr` (`T[]`): The array to flatten.
- `iteratee` (`T[]`): A function that maps each array element.
- `depth` (`D`): The depth to flatten, which defaults to 1.
### Returns
(`Array<FlatArray<U[], D>>`): A new array with each element mapped and flattened to the desired depth.
## Examples
```typescript
const array = [1, 2, 3];
const result1 = flatMap(array, item => [item, item], 1);
// Return [1, 1, 2, 2, 3, 3]
const result2 = flatMap(array, item => [[item, item]], 2);
// Return [1, 1, 2, 2, 3, 3]
const result3 = flatMap(array, item => [[[item, item]]], 3);
// Return [1, 1, 2, 2, 3, 3]
```

36
src/array/flatMap.spec.ts Normal file
View File

@ -0,0 +1,36 @@
import { describe, expect, it } from 'vitest';
import { flatMap } from './flatMap';
describe('flatMap', () => {
const originArr = [1, 2, 3];
it('should map and flatten array of numbers with default depth', () => {
const iteratee = (item: number) => [item, item];
const expectedArr = [1, 1, 2, 2, 3, 3];
expect(flatMap(originArr, iteratee)).toEqual(expectedArr);
});
it('should map and flatten array of numbers with specified depth', () => {
const iteratee = (item: number) => [[[item, item]]];
const expectedArr1 = [[[1, 1]], [[2, 2]], [[3, 3]]];
expect(flatMap(originArr, iteratee, 1)).toEqual(expectedArr1);
const expectedArr2 = [
[1, 1],
[2, 2],
[3, 3],
];
expect(flatMap(originArr, iteratee, 2)).toEqual(expectedArr2);
const expectedArr3 = [1, 1, 2, 2, 3, 3];
expect(flatMap(originArr, iteratee, 3)).toEqual(expectedArr3);
});
it('should handle empty array', () => {
const emptyArr: number[] = [];
const result = flatMap(emptyArr, item => [item, item]);
expect(result).toEqual([]);
});
});

29
src/array/flatMap.ts Normal file
View File

@ -0,0 +1,29 @@
import { flatten } from './flatten';
/**
* Maps each element in the array using the iteratee function and flattens the result up to the specified depth.
*
* @template T - The type of elements within the array.
* @template U - The type of elements within the returned array from the iteratee function.
* @template D - The depth to which the array should be flattened.
* @param {T[]} arr - The array to flatten.
* @param {(item: T) => U} iteratee - The function that produces the new array elements.
* @param {D} depth - The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.
* @returns {Array<FlatArray<U[], D>>} The new array with the mapped and flattened elements.
*
* @example
* const arr = [1, 2, 3];
*
* flatMap(arr, (item: number) => [item, item]);
* // [1, 1, 2, 2, 3, 3]
*
* flatMap(arr, (item: number) => [[item, item]], 2);
* // [1, 1, 2, 2, 3, 3]
*/
export function flatMap<T, U, D extends number>(
arr: readonly T[],
iteratee: (item: T) => U,
depth = 1 as D
): Array<FlatArray<U[], D>> {
return flatten(arr.map(item => iteratee(item)), depth);
}

View File

@ -9,6 +9,7 @@ export { dropRight } from './dropRight.ts';
export { dropRightWhile } from './dropRightWhile.ts';
export { dropWhile } from './dropWhile.ts';
export { fill } from './fill.ts';
export { flatMap } from './flatMap.ts';
export { flatten } from './flatten.ts';
export { flattenDeep } from './flattenDeep.ts';
export { forEachRight } from './forEachRight.ts';