Skip to content

Commit

Permalink
fix(utils): invert 한글 화 및 스펙 변경 (#573)
Browse files Browse the repository at this point in the history
* fix(utils): groupBy 한글화

* fix(utils): invert 한글 화 및 스펙 변경
  • Loading branch information
ssi02014 authored Nov 6, 2024
1 parent bd1b2c5 commit ca40d96
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 189 deletions.
5 changes: 5 additions & 0 deletions .changeset/red-lobsters-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/utils': patch
---

fix(utils): invert 스펙 변경 - @ssi02014
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# groupBy

배열의 요소들을 제공된 콜백 함수 `callbackFn`에 따라 그룹화하여, 각 키에 해당하는 항목들의 배열을 포함하는 객체를 반환합니다.
배열을 주어진 기준에 따라 그룹화합니다.

`iteratee` 함수를 전달하여 반환된 키를 기준으로 항목들을 그룹화합니다. 각 키는 그룹화된 항목 배열을 포함하는 객체의 속성으로 할당됩니다.

## Code

Expand All @@ -12,24 +14,25 @@

|이름|hz|mean|성능|
|------|---|---|---|
|modern-kit/groupBy|20,066.27|0.0498|`fastest`|
|lodash/groupBy|7,716.57|0.1296|`slowest`|
|modern-kit/groupBy|6,982,132.03|0.0001|`fastest`|
|lodash/groupBy|4,223,901.69|0.0002|`slowest`|

- **modern-kit/groupBy**
- `2.60x` faster than lodash/groupBy
- `1.65x` 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[]>
arr: T[] | readonly T[],
iteratee: (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' },
Expand All @@ -39,14 +42,14 @@ const items = [
];
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' },
// ],
// fruit: [
// { category: 'fruit', name: 'apple' },
// { category: 'fruit', name: 'banana' },
// { category: 'fruit', name: 'pear' },
// ],
// vegetable: [
// { category: 'vegetable', name: 'carrot' },
// { category: 'vegetable', name: 'broccoli' },
// ],
// };
```
51 changes: 28 additions & 23 deletions docs/docs/utils/object/invert.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
# invert

객체의 `key``value`를 뒤집는 함수입니다.
주어진 객체의 각 키와 값을 반전하여 새로운 객체를 생성합니다.

필요 시 2번째 인자로 함수(`keyTransformer`)를 넘겨 key를 직접 핸들링 할 수 있습니다.
기본적으로 객체의 키와 값을 반전하지만, `iteratee` 함수를 제공하면 각 값에 대해 변형된 키를 생성하여 반전할 수 있습니다.

<br />

## Code
[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/object/invert/index.ts)

### Default
|이름|hz|mean|성능|
|------|---|---|---|
|modern-kit/invert|6,119,008.75|0.0002|`fastest`|
|lodash/invert|4,459,920.52|0.0003|`slowest`|

- **modern-kit/invert**
- `1.37x` faster than **lodash/invert**

### with iteratee
|이름|hz|mean|성능|
|------|---|---|---|
|modern-kit/invert|4,154,655.71|0.0003|`fastest`|
|lodash/invertBy|2,262,596.79|0.0004|`slowest`|

- **modern-kit/invert**
- `1.84x` faster than **lodash/invertBy**

## Interface
```ts title="typescript"
const invert: <
K extends PropertyKey,
V,
TK extends PropertyKey = V extends PropertyKey ? V : PropertyKey
>(
function invert<K extends PropertyKey, V extends PropertyKey>(
obj: Record<K, V>
): Record<V, K>;

function invert<K extends PropertyKey, V, TK extends PropertyKey>(
obj: Record<K, V>,
keyTransformer?: (value: V) => TK
) => Record<TK, Exclude<K, symbol>>;
iteratee: (iterateData: { value: V; key: K; obj: Record<K, V> }) => TK
): Record<TK, K>;
```

## Usage
Expand All @@ -33,20 +51,7 @@ invert(obj);
// type: Record<number, "a" | "b" | "c">
```

### KeyTransformer
```ts title="typescript"
import { invert } from '@modern-kit/utils';

const obj = { a: [1, 2, 3], b: [4, 5, 6] };

invert(obj, (value) => {
return JSON.stringify(value);
});
// value: { '[1,2,3]': 'a', '[4,5,6]': 'b' }
// type: Record<string, "a" | "b">
```

### const assertion
### with iteratee
```ts title="typescript"
import { invert } from '@modern-kit/utils';

Expand Down
21 changes: 21 additions & 0 deletions packages/utils/src/array/groupBy/groupBy.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { bench, describe } from 'vitest';
import { groupBy } from '.';
import { groupBy as groupByLodash } from 'lodash-es';

describe('groupBy', () => {
const array = [
{ category: 'fruit', name: 'apple' },
{ category: 'fruit', name: 'banana' },
{ category: 'vegetable', name: 'carrot' },
{ category: 'fruit', name: 'pear' },
{ category: 'vegetable', name: 'broccoli' },
];

bench('modern-kit/groupBy', () => {
groupBy(array, (item) => item.category);
});

bench('lodash/groupBy', () => {
groupByLodash(array, (item) => item.category);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
import { groupBy } from '.';

describe('groupBy', () => {
it('should group elements by a given key', () => {
it('주어진 key로 배열을 그룹화해야 합니다.', () => {
const items = [
{ category: 'fruit', name: 'apple' },
{ category: 'fruit', name: 'banana' },
Expand All @@ -11,7 +11,6 @@ describe('groupBy', () => {
{ category: 'vegetable', name: 'broccoli' },
];

const actual = groupBy(items, (item) => item.category);
const expected = {
fruit: [
{ category: 'fruit', name: 'apple' },
Expand All @@ -24,27 +23,24 @@ describe('groupBy', () => {
],
};

expect(actual).toEqual(expected);
expect(groupBy(items, (item) => item.category)).toEqual(expected);
});

it('should handle an empty array', () => {
it('빈 배열을 처리 할 수 있어야 합니다.', () => {
const items: Array<Record<string, string>> = [];

const actual = groupBy(items, (item) => item.category);
const expected = {};

expect(actual).toEqual(expected);
expect(groupBy(items, (item) => item.category)).toEqual(expected);
});

it('should group handle numeric key', () => {
it('숫자 키를 그룹화해서 처리해야 합니다.', () => {
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' },
Expand All @@ -56,32 +52,6 @@ describe('groupBy', () => {
],
};

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);
expect(groupBy(items, (item) => item.category)).toEqual(expected);
});
});
55 changes: 55 additions & 0 deletions packages/utils/src/array/groupBy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @description 배열을 주어진 기준에 따라 그룹화합니다.
*
* `iteratee` 함수를 전달하여 반환된 키를 기준으로 항목들을 그룹화합니다. 각 키는 그룹화된 항목 배열을 포함하는 객체의 속성으로 할당됩니다.
*
* 24년 3월 js 신규 스펙으로 groupBy가 제공되지만 버전 호환성을 위해 해당 함수가 사용 될 수 있습니다.
* @see https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy
*
* @template T - 배열 항목의 타입을 나타냅니다.
* @template K - 그룹화 기준으로 사용할 키의 타입입니다.
* @param {T[] | readonly T[]} arr - 그룹화를 진행할 항목들의 배열입니다.
* @param {(item: T) => K} iteratee - 각 항목에 대해 그룹화 키를 반환하는 함수입니다.
* @returns {Record<K, T[]>} - 각 키가 그룹화된 항목 배열을 가지는 객체를 반환합니다.
*
* @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>(
arr: T[] | readonly T[],
iteratee: (item: T) => K
): Record<K, T[]> {
const group = {} as Record<K, T[]>;

for (let i = 0; i < arr.length; i++) {
const item = arr[i];
const key = iteratee(item);

if (group[key] == null) {
group[key] = [];
}

group[key].push(item);
}

return group;
}
1 change: 1 addition & 0 deletions packages/utils/src/array/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export * from './flatten';
export * from './flattenDeep';
export * from './flattenDeepThenMap';
export * from './forEachRight';
export * from './groupBy';
export * from './intersection';
export * from './mapRight';
export * from './partition';
Expand Down
17 changes: 0 additions & 17 deletions packages/utils/src/object/groupBy/groupBy.bench.ts

This file was deleted.

51 changes: 0 additions & 51 deletions packages/utils/src/object/groupBy/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/utils/src/object/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export * from './deleteFalsyProperties';
export * from './findKey';
export * from './findLastKey';
export * from './groupBy';
export * from './invert';
export * from './mapKeys';
export * from './mapValues';
Expand Down
Loading

0 comments on commit ca40d96

Please sign in to comment.