Skip to content

Commit

Permalink
Fix/difference (#559)
Browse files Browse the repository at this point in the history
* fix(utils): uniq 함수 개선 및 한글화

* fix(utils): uniq/union 기능 및 타입 개선

* imp(utils): difference 성능 개선 및 문서 개선

* docs(utils): reverseString 문서 및 테스트 코드 수정

* imp: compact 기능 개선

* fix: isEqual for문으로 변경

* chore: remove changesetlog

* imp: isEqual 한글화
  • Loading branch information
ssi02014 authored Nov 4, 2024
1 parent e496324 commit 5601799
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 55 deletions.
5 changes: 5 additions & 0 deletions .changeset/purple-pots-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/utils': patch
---

imp(utils): difference 성능 개선 및 문서 개선 - @ssi02014
38 changes: 27 additions & 11 deletions docs/docs/utils/array/difference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

첫번째 배열을 기준으로 두번째 배열과 `중복된 요소를 제외해 고유한 값만을 갖는` 새로운 배열을 반환하는 함수입니다.

기본적으로 `원시 값`에 대해서만 중복 요소를 판단하며, 필요 시 3번째 인자인 `iteratee` 함수 결과로 중복 요소임을 판단 할 수 있습니다.
기본적으로 `원시 값`에 대해서만 중복 요소를 판단하지만, `iteratee` 함수를 제공하여 각 요소를 변환한 후 결과 값을 기반으로 비교할 수 있습니다.

<br />

Expand All @@ -13,13 +13,23 @@
- `hz`: 초당 작업 수
- `mean`: 평균 응답 시간(ms)

### Default
|이름|hz|mean|성능|
|------|---|---|---|
|modern-kit/difference|9,251,611.33|0.0001|`fastest`|
|lodash/difference|4,113,377.61|0.0002|`slowest`|

- **modern-kit/difference**
- `2.25x` faster than **lodash/difference**

### with iteratee
|이름|hz|mean|성능|
|------|---|---|---|
|modern-kit/difference|2,768,995.87|0.0004|`fastest`|
|lodash/differenceBy|1,538,329.26|0.0007|`slowest`|
|modern-kit/difference|11,133,900.99|0.0001|`fastest`|
|lodash/differenceBy|3,211,808.45|0.0002|`slowest`|

- **modern-kit/difference**
- `1.80x` faster than lodash/differenceBy
- `3.47x` faster than **lodash/differenceBy**

## Interface
```ts title="typescript"
Expand All @@ -35,26 +45,32 @@ const difference: <T, U = T>(
```ts title="typescript"
import { difference } from '@modern-kit/utils';

difference([1, 2, 3, 4], [1, 2, 3, 5]); // [4]
const arr1 = [1, 2, 3, 4];
const arr2 = [2, 4];

difference(arr1, arr2); // [1, 3]
```

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

const firstArr = [
const arr1 = [
{ id: 1, name: 'john' },
{ id: 2, name: 'dylan' },
{ id: 3, name: 'modern' },
{ id: 4, name: 'gromit' },
];
const secondArr = [
{ id: 1, name: 'john' },
{ id: 3, name: 'gromit' },
const arr2 = [
{ id: 2, name: 'john' },
{ id: 4, name: 'gromit' },
];

difference(firstArr, secondArr, (item) => item.id);
difference(arr1, arr2, (item) => item.id);
/*
[
{ id: 2, name: 'dylan' },
{ id: 1, name: 'john' },
{ id: 3, name: 'modern' },
]
*/
```
2 changes: 1 addition & 1 deletion docs/docs/utils/string/reverseString.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

## Interface
```ts title="typescript"
const reverseString: (value: string) => string
function reverseString(value: string): string
```

## Usage
Expand Down
4 changes: 3 additions & 1 deletion packages/utils/src/array/compact/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ type Retained<T> = Exclude<T, Removable>;
export function compact<T>(arr: T[] | readonly T[]): Retained<T>[] {
const result: Retained<T>[] = [];

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

if (item) {
result.push(item as Retained<T>);
}
Expand Down
33 changes: 24 additions & 9 deletions packages/utils/src/array/difference/difference.bench.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import { bench, describe } from 'vitest';
import { differenceBy as differenceByLodash } from 'lodash-es';
import {
differenceBy as differenceByLodash,
difference as differenceLodash,
} from 'lodash-es';
import { difference } from '.';

const createTestArr = (length: number) => {
return Array.from({ length }, () => ({
id: Math.floor(Math.random() * 10),
}));
};

describe('difference', () => {
const arr1 = createTestArr(20);
const arr2 = createTestArr(10);
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [2, 3, 4];
bench('modern-kit/difference', () => {
difference(arr1, arr2);
});

bench('lodash/difference', () => {
differenceLodash(arr1, arr2);
});
});

describe('difference with iteratee', () => {
const arr1 = [
{ id: 1, name: 'john' },
{ id: 2, name: 'gromit' },
];
const arr2 = [
{ id: 1, name: 'john' },
{ id: 3, name: 'dylan' },
];

bench('modern-kit/difference', () => {
difference(arr1, arr2, (item) => item.id);
Expand Down
8 changes: 5 additions & 3 deletions packages/utils/src/array/difference/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* @description 첫 번째 배열에서 두 번째 배열에 없는 요소들을 반환하는 함수입니다.
* 선택적으로 제공된 `iteratee` 함수를 사용하여 각 요소를 변환한 후 비교할 수 있습니다.
*
* `iteratee` 함수를 제공하여 각 요소를 변환한 후 결과 값을 기반으로 비교할 수 있습니다.
*
* @template T - 첫 번째 배열의 요소 타입입니다.
* @template U - `iteratee` 함수가 반환하는 타입으로, 기본값은 `T`와 같습니다.
Expand Down Expand Up @@ -38,8 +39,9 @@ export function difference<T, U = T>(
iteratee ? secondArr.map(iteratee) : secondArr
);

for (const item of firstArr) {
const mappedItem = iteratee ? iteratee(item) : item;
for (let i = 0; i < firstArr.length; i++) {
const item = firstArr[i];
const mappedItem = iteratee ? iteratee(firstArr[i]) : firstArr[i];

if (!secondSet.has(mappedItem)) {
result.push(item);
Expand Down
11 changes: 10 additions & 1 deletion packages/utils/src/string/reverseString/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
export function reverseString(value: string) {
/**
* @description 주어진 문자열을 뒤집어 반환하는 함수입니다.
*
* @param {string} value - 뒤집을 문자열입니다.
* @returns {string} 뒤집힌 문자열입니다. 입력이 없거나 빈 문자열인 경우, 빈 문자열을 반환합니다.
*
* @example
* reverseString("hello"); // "olleh"
*/
export function reverseString(value: string): string {
if (!value) return '';

return [...value].reverse().join('');
Expand Down
12 changes: 3 additions & 9 deletions packages/utils/src/string/reverseString/reverseString.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,21 @@ import { describe, it, expect } from 'vitest';
import { reverseString } from '.';

describe('reverseString', () => {
it('should return the empty string for a invalid value', () => {
const reversedString = reverseString(undefined as unknown as string);

expect(reversedString).toBe('');
});

it('should return the reversed string for a normal string', () => {
it('주어진 문자열에 대해 반전된 문자열을 반환해야 합니다.', () => {
const normalString = 'ABC가나다';
const reversedString = reverseString(normalString);

expect(reversedString).toBe('다나가CBA');
});

it('should return the reversed string for a string with special characters', () => {
it('특수 문자가 포함된 문자열에 대해 반전된 문자열을 반환해야 합니다.', () => {
const stringWithSpecialCharacter = 'A!B@C';
const reversedString = reverseString(stringWithSpecialCharacter);

expect(reversedString).toBe('C@B!A');
});

it('should return the reversed string for a string with unicode characters', () => {
it('유니코드 문자가 포함된 문자열에 대해 반전된 문자열을 반환해야 합니다.', () => {
const stringWithUnicodeCharacter = 'foo 𝌆 bar';
const reversedString = reverseString(stringWithUnicodeCharacter);

Expand Down
26 changes: 7 additions & 19 deletions packages/utils/src/validator/isEqual/isEqual.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { describe, expect, it } from 'vitest';
import { isEqual } from '.';

describe('isEqual', () => {
it('should return true if primitive types are deeply equal', () => {
it('원시 값을 깊은 비교 시 동일하면 true, 동일하지 않으면 false를 반환해야 합니다.', () => {
expect(isEqual(1, 1)).toBeTruthy();
expect(isEqual('a', 'a')).toBeTruthy();

expect(isEqual(1, 2)).toBeFalsy();
expect(isEqual('a', 'b')).toBeFalsy();
});

it('should return true if objects or arrays are deeply equal', () => {
it('객체/배열을 깊은 비교 시 동일하면 true, 동일하지 않으면 false를 반환해야 합니다.', () => {
expect(isEqual({ a: 1, b: { c: 1 } }, { a: 1, b: { c: 1 } })).toBeTruthy();
expect(
isEqual(
Expand Down Expand Up @@ -45,7 +45,7 @@ describe('isEqual', () => {
).toBeFalsy();
});

it('should return true if function are deeply equal', () => {
it('함수를 깊은 비교 시 동일하면 true, 동일하지 않으면 false를 반환해야 합니다.', () => {
const origin = () => 1;
const target = origin;
expect(
Expand All @@ -63,7 +63,7 @@ describe('isEqual', () => {
).toBeFalsy();
});

it('should return true if two objects with circular references are deeply equal', () => {
it('순환 참조를 가진 두 객체가 깊은 비교 시 동일하면 true, 동일하지 않으면 false를 반환해야 합니다.', () => {
const objA: any = { a: 1 };
const objB: any = { a: 1 };

Expand All @@ -73,13 +73,13 @@ describe('isEqual', () => {
expect(isEqual(objA, objB)).toBeTruthy();
});

it('should return true if null or undefined are deeply equal', () => {
it('null/undefined/NaN를 깊은 비교 시 동일하면 true, 동일하지 않으면 false를 반환해야 합니다.', () => {
expect(isEqual(null, null)).toBeTruthy();
expect(isEqual(undefined, undefined)).toBeTruthy();
expect(isEqual(null, undefined)).toBeFalsy();
});

it('should return true if Set or Map are deeply equal', () => {
it('Set/Map 깊은 비교 시 동일하면 true, 동일하지 않으면 false를 반환해야 합니다.', () => {
// truthy
expect(
isEqual(
Expand Down Expand Up @@ -130,18 +130,6 @@ describe('isEqual', () => {
it('should return true for identical arrays with different element order', () => {
const arr1 = [1, 2, 3];
const arr2 = [3, 2, 1];
expect(isEqual(new Set(arr1), new Set(arr2))).toBe(false);
});

it('should return true for NaN values', () => {
expect(isEqual(NaN, NaN)).toBe(true);
});

it('should return false for NaN and a number', () => {
expect(isEqual(NaN, 1)).toBe(false);
});

it('should return false for NaN and undefined', () => {
expect(isEqual(NaN, undefined)).toBe(false);
expect(isEqual(new Set(arr1), new Set(arr2))).toBeFalsy();
});
});
4 changes: 3 additions & 1 deletion packages/utils/src/validator/isEqual/isEqual.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ const compareObjectOrArray = (
return false;
}

for (const key of sourceKeys) {
for (let i = 0; i < sourceKeys.length; i++) {
const key = sourceKeys[i];

if (
!targetKeys.includes(key) ||
!isEqualInternal(source[key], target[key], visited)
Expand Down

0 comments on commit 5601799

Please sign in to comment.