-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(isNumericString): Add isNumericString * Update packages/utils/src/validator/isNumericString/index.ts * Update docs/docs/utils/validator/isNumericString.md * Create little-roses-itch.md * Update packages/utils/src/validator/isNumericString/index.ts * feat(groupBy): Add groupBy * Update packages/utils/src/object/groupBy/index.ts * Update docs/docs/utils/object/groupBy.md * Create blue-rules-rule.md --------- Co-authored-by: Gromit (전민재) <64779472+ssi02014@users.noreply.github.com>
- Loading branch information
1 parent
1d0d473
commit e031af0
Showing
6 changed files
with
213 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@modern-kit/utils": minor | ||
--- | ||
|
||
feat(groupBy): Add groupBy - @haejunejung |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# groupBy | ||
|
||
배열의 요소들을 제공된 콜백 함수 `callbackFn`에 따라 그룹화하여, 각 키에 해당하는 항목들의 배열을 포함하는 객체를 반환합니다. | ||
|
||
## Code | ||
|
||
[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/object/groupBy/index.ts) | ||
|
||
## Benchmark | ||
- `hz`: 초당 작업 수 | ||
- `mean`: 평균 응답 시간(ms) | ||
|
||
|이름|hz|mean|성능| | ||
|------|---|---|---| | ||
|modern-kit/groupBy|20,066.27|0.0498|`fastest`| | ||
|lodash/groupBy|7,716.57|0.1296|`slowest`| | ||
|
||
- **modern-kit/groupBy** | ||
- `2.60x` faster than lodash/groupBy | ||
|
||
## Interface | ||
```ts title="typescript" | ||
function groupBy<T, K extends PropertyKey>( | ||
items: T[] | readonly T[], | ||
callbackFn: (item: T) => K | ||
): Record<K, T[]> | ||
``` | ||
|
||
## Usage | ||
|
||
```ts title="typescript" | ||
import { groupBy } from '@modern-kit/utils'; | ||
const items = [ | ||
{ category: 'fruit', name: 'apple' }, | ||
{ category: 'fruit', name: 'banana' }, | ||
{ category: 'vegetable', name: 'carrot' }, | ||
{ category: 'fruit', name: 'pear' }, | ||
{ category: 'vegetable', name: 'broccoli' }, | ||
]; | ||
const group = groupBy(items, (item) => item.category); | ||
// { | ||
// fruit: [ | ||
// { category: 'fruit', name: 'apple' }, | ||
// { category: 'fruit', name: 'banana' }, | ||
// { category: 'fruit', name: 'pear' }, | ||
// ], | ||
// vegetable: [ | ||
// { category: 'vegetable', name: 'carrot' }, | ||
// { category: 'vegetable', name: 'broccoli' }, | ||
// ], | ||
// }; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { bench, describe } from 'vitest'; | ||
import { groupBy } from '.'; | ||
import { groupBy as groupByLodash } from 'lodash-es'; | ||
|
||
describe('groupBy', () => { | ||
const obj = Array.from({ length: 10000 }, () => { | ||
return { category: 'fruit', name: 'apple' }; | ||
}); | ||
|
||
bench('modern-kit/groupBy', () => { | ||
groupBy(obj, (item) => item.category); | ||
}); | ||
|
||
bench('lodash/groupBy', () => { | ||
groupByLodash(obj, (item) => item.category); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { describe, expect, it } from 'vitest'; | ||
import { groupBy } from '.'; | ||
|
||
describe('groupBy', () => { | ||
it('should group elements by a given key', () => { | ||
const items = [ | ||
{ category: 'fruit', name: 'apple' }, | ||
{ category: 'fruit', name: 'banana' }, | ||
{ category: 'vegetable', name: 'carrot' }, | ||
{ category: 'fruit', name: 'pear' }, | ||
{ category: 'vegetable', name: 'broccoli' }, | ||
]; | ||
|
||
const actual = groupBy(items, (item) => item.category); | ||
const expected = { | ||
fruit: [ | ||
{ category: 'fruit', name: 'apple' }, | ||
{ category: 'fruit', name: 'banana' }, | ||
{ category: 'fruit', name: 'pear' }, | ||
], | ||
vegetable: [ | ||
{ category: 'vegetable', name: 'carrot' }, | ||
{ category: 'vegetable', name: 'broccoli' }, | ||
], | ||
}; | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
|
||
it('should handle an empty array', () => { | ||
const items: Array<Record<string, string>> = []; | ||
|
||
const actual = groupBy(items, (item) => item.category); | ||
const expected = {}; | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
|
||
it('should group handle numeric key', () => { | ||
const items = [ | ||
{ category: 1, name: 'apple' }, | ||
{ category: 2, name: 'banana' }, | ||
{ category: 1, name: 'carrot' }, | ||
{ category: 2, name: 'pear' }, | ||
]; | ||
|
||
const actual = groupBy(items, (item) => item.category); | ||
const expected = { | ||
'1': [ | ||
{ category: 1, name: 'apple' }, | ||
{ category: 1, name: 'carrot' }, | ||
], | ||
'2': [ | ||
{ category: 2, name: 'banana' }, | ||
{ category: 2, name: 'pear' }, | ||
], | ||
}; | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
|
||
it('should group handle symbol key', () => { | ||
const symbolA = Symbol('A'); | ||
const symbolB = Symbol('B'); | ||
|
||
const items = [ | ||
{ category: symbolA, name: 'apple' }, | ||
{ category: symbolB, name: 'banana' }, | ||
{ category: symbolA, name: 'carrot' }, | ||
{ category: symbolB, name: 'pear' }, | ||
]; | ||
|
||
const actual = groupBy(items, (item) => item.category); | ||
const expected = { | ||
[symbolA]: [ | ||
{ category: symbolA, name: 'apple' }, | ||
{ category: symbolA, name: 'carrot' }, | ||
], | ||
[symbolB]: [ | ||
{ category: symbolB, name: 'banana' }, | ||
{ category: symbolB, name: 'pear' }, | ||
], | ||
}; | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/** | ||
* @description | ||
* 배열의 요소들을 제공된 콜백 함수 `callbackFn`에 따라 그룹화하여, 각 키에 해당하는 항목들의 배열을 포함하는 객체를 반환합니다. | ||
* | ||
* @template T - 배열 항목의 타입을 나타냅니다. | ||
* @template K - 그룹화 키의 타입을 나타냅니다. `PropertyKey`로 제한되어 있어, 문자열, 숫자, 심볼 등 가능한 모든 키 타입을 사용할 수 있습니다. | ||
* @param {T[] | readonly T[]} items - 그룹화를 진행할 항목들의 배열입니다. | ||
* @param {(item: T) => K} callbackFn - 각 항목에 대해 그룹화 키를 반환하는 함수입니다. | ||
* @returns {Record<K, T[]>} - 각 키가 콜백 함수 `callbackFn`의 결과이고, 값이 해당 키에 속하는 항목들의 배열인 객체를 반환합니다. | ||
* | ||
* @example | ||
* const array = [ | ||
* { category: 'fruit', name: 'apple' }, | ||
* { category: 'fruit', name: 'banana' }, | ||
* { category: 'vegetable', name: 'carrot' }, | ||
* { category: 'fruit', name: 'pear' }, | ||
* { category: 'vegetable', name: 'broccoli' }, | ||
* ]; | ||
* | ||
* const group = groupBy(array, (item) => item.category); | ||
* // { | ||
* // fruit: [ | ||
* // { category: 'fruit', name: 'apple' }, | ||
* // { category: 'fruit', name: 'banana' }, | ||
* // { category: 'fruit', name: 'pear' }, | ||
* // ], | ||
* // vegetable: [ | ||
* // { category: 'vegetable', name: 'carrot' }, | ||
* // { category: 'vegetable', name: 'broccoli' }, | ||
* // ], | ||
* // } | ||
*/ | ||
|
||
export function groupBy<T, K extends PropertyKey>( | ||
items: T[] | readonly T[], | ||
callbackFn: (item: T) => K | ||
): Record<K, T[]> { | ||
const group = {} as Record<K, T[]>; | ||
|
||
for (const item of items) { | ||
const key = callbackFn(item); | ||
|
||
if (!(key in group)) { | ||
group[key] = []; | ||
} | ||
|
||
group[key].push(item); | ||
} | ||
|
||
return group; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters