Skip to content

Commit

Permalink
feat(isEqualWith): Implement isEqualWith
Browse files Browse the repository at this point in the history
  • Loading branch information
raon0211 committed Oct 1, 2024
1 parent 1bda274 commit 3462a84
Show file tree
Hide file tree
Showing 18 changed files with 925 additions and 310 deletions.
100 changes: 50 additions & 50 deletions benchmarks/performance/isEqual.bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,55 @@ import { isEqual as isEqualLodash_ } from 'lodash';
const isEqualToolkit = isEqualToolkit_;
const isEqualLodash = isEqualLodash_;

// describe('isEqual primitives', () => {
// bench('es-toolkit/isEqual', () => {
// isEqualToolkit(1, 1);
// isEqualToolkit(NaN, NaN);
// isEqualToolkit(+0, -0);
describe('isEqual primitives', () => {
bench('es-toolkit/isEqual', () => {
isEqualToolkit(1, 1);
isEqualToolkit(NaN, NaN);
isEqualToolkit(+0, -0);

// isEqualToolkit(true, true);
// isEqualToolkit(true, false);
isEqualToolkit(true, true);
isEqualToolkit(true, false);

// isEqualToolkit('hello', 'hello');
// isEqualToolkit('hello', 'world');
// });
isEqualToolkit('hello', 'hello');
isEqualToolkit('hello', 'world');
});

// bench('lodash/isEqual', () => {
// isEqualLodash(1, 1);
// isEqualLodash(NaN, NaN);
// isEqualLodash(+0, -0);
bench('lodash/isEqual', () => {
isEqualLodash(1, 1);
isEqualLodash(NaN, NaN);
isEqualLodash(+0, -0);

// isEqualLodash(true, true);
// isEqualLodash(true, false);
isEqualLodash(true, true);
isEqualLodash(true, false);

// isEqualLodash('hello', 'hello');
// isEqualLodash('hello', 'world');
// });
// });
isEqualLodash('hello', 'hello');
isEqualLodash('hello', 'world');
});
});

// describe('isEqual dates', () => {
// bench('es-toolkit/isEqual', () => {
// isEqualToolkit(new Date('2020-01-01'), new Date('2020-01-01'));
// isEqualToolkit(new Date('2020-01-01'), new Date('2021-01-01'));
// });
describe('isEqual dates', () => {
bench('es-toolkit/isEqual', () => {
isEqualToolkit(new Date('2020-01-01'), new Date('2020-01-01'));
isEqualToolkit(new Date('2020-01-01'), new Date('2021-01-01'));
});

// bench('lodash', () => {
// isEqualLodash(new Date('2020-01-01'), new Date('2020-01-01'));
// isEqualLodash(new Date('2020-01-01'), new Date('2021-01-01'));
// });
// });
bench('lodash', () => {
isEqualLodash(new Date('2020-01-01'), new Date('2020-01-01'));
isEqualLodash(new Date('2020-01-01'), new Date('2021-01-01'));
});
});

// describe('isEqual RegExps', () => {
// bench('es-toolkit/isEqual', () => {
// isEqualToolkit(/hello/g, /hello/g);
// isEqualToolkit(/hello/g, /hello/i);
// });
describe('isEqual RegExps', () => {
bench('es-toolkit/isEqual', () => {
isEqualToolkit(/hello/g, /hello/g);
isEqualToolkit(/hello/g, /hello/i);
});

// bench('lodash', () => {
// isEqualLodash(/hello/g, /hello/g);
// isEqualLodash(/hello/g, /hello/i);
// })
// })
bench('lodash', () => {
isEqualLodash(/hello/g, /hello/g);
isEqualLodash(/hello/g, /hello/i);
});
});

describe('isEqual objects', () => {
bench('es-toolkit/isEqual', () => {
Expand All @@ -69,14 +69,14 @@ describe('isEqual objects', () => {
});
});

// describe('isEqual arrays', () => {
// bench('es-toolkit/isEqual', () => {
// isEqualToolkit([1, 2, 3], [1, 2, 3]);
// isEqualToolkit([1, 2, 3], [1, 2, 4]);
// });
describe('isEqual arrays', () => {
bench('es-toolkit/isEqual', () => {
isEqualToolkit([1, 2, 3], [1, 2, 3]);
isEqualToolkit([1, 2, 3], [1, 2, 4]);
});

// bench('lodash', () => {
// isEqualLodash([1, 2, 3], [1, 2, 3]);
// isEqualLodash([1, 2, 3], [1, 2, 4]);
// });
// })
bench('lodash', () => {
isEqualLodash([1, 2, 3], [1, 2, 3]);
isEqualLodash([1, 2, 3], [1, 2, 4]);
});
});
6 changes: 3 additions & 3 deletions docs/ja/reference/function/flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ const combined = flow(add, square);
console.log(combined(1, 2)); // 9
```

## Lodash 互換性
## Lodash 互換性

`es-toolkit/compat` から `flow` をインポートすると、Lodash と互換になります。

- `flow` は関数の配列と個別の関数の両方を引数として受け入れます。
- `flow` は関数の配列と個別の関数の両方を引数として受け入れます。
- 提供された関数が関数でない場合、`flow` はエラーをスローします。

```typescript
Expand All @@ -65,4 +65,4 @@ const double = (n: number) => n * 2;

const combined = flow([add, square], double);
console.log(combined(1, 2)); // => 18
```
```
57 changes: 57 additions & 0 deletions docs/ja/reference/predicate/isEqualWith.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# isEqualWith

二つの値が与えられた比較関数を使って等しいかどうかを比較します。

比較関数を提供することで、二つの値が等しいかどうかを検証する方法を細かく調整できます。
与えられた比較関数が `true` を返すと、二つの値は等しいと見なされます。 `false` を返すと、二つの値は異なると見なされます。
`undefined` を返すと、[isEqual](./isEqual.md) が提供するデフォルトの方法で二つの値を比較します。

オブジェクト、配列、`Map``Set` のように複数の要素を持つ場合でも、与えられた比較関数を使って要素間の値を比較します。

基本的な比較方法の上に、複雑な比較を処理するための方法を定義できるため、柔軟に二つの値を比較できます。

## インターフェース

```typescript
function isEqualWith(
a: any,
b: any,
areValuesEqual: (
x: any,
y: any,
property?: PropertyKey,
xParent?: any,
yParent?: any,
stack?: Map<any, any>
) => boolean | void
): boolean;
```

### パラメータ

- `a` (`unknown`): 比較する最初の値。
- `b` (`unknown`): 比較する2番目の値。
- `areValuesEqual` (`(x: any, y: any, property?: PropertyKey, xParent?: any, yParent?: any, stack?: Map<any, any>) => boolean | void`): 2つの値を比較する方法を示す比較関数。2つの値が等しいかどうかを示すブール値を返すことができます。`undefined`を返すと、デフォルトの方法で2つの値を比較します。
- `x`: 最初のオブジェクト `a` に属する値。
- `y`: 2番目のオブジェクト `b` に属する値。
- `property`: `x``y` を取得するために使用されたプロパティキー。
- `xParent`: 最初の値 `x` の親。
- `yParent`: 2番目の値 `y` の親。
- `stack`: 循環参照を処理するための内部スタック(`Map`)。

### 戻り値

(`boolean`): 値がカスタマイザーに従って等しい場合は `true`、それ以外の場合は `false`

##

```typescript
const customizer = (a, b) => {
if (typeof a === 'string' && typeof b === 'string') {
return a.toLowerCase() === b.toLowerCase();
}
};
isEqualWith('Hello', 'hello', customizer); // true
isEqualWith({ a: 'Hello' }, { a: 'hello' }, customizer); // true
isEqualWith([1, 2, 3], [1, 2, 3], customizer); // true
```
6 changes: 3 additions & 3 deletions docs/ko/reference/function/flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ const combined = flow(add, square);
console.log(combined(1, 2)); // 9
```

## Lodash와 호환성
## Lodash와 호환성

`es-toolkit/compat`에서 `flow`를 가져오면 lodash와 완전히 호환돼요.

- `flow`는 파라미터로 개별 함수뿐만 아니라 함수들의 배열도 받을 수 있어요.
- `flow`는 파라미터로 개별 함수뿐만 아니라 함수들의 배열도 받을 수 있어요.
- 파라미터로 함수가 아닌 값이 주어지면 `flow`는 오류를 발생시켜요.

```typescript
Expand All @@ -65,4 +65,4 @@ const double = (n: number) => n * 2;

const combined = flow([add, square], double);
console.log(combined(1, 2)); // => 18
```
```
8 changes: 4 additions & 4 deletions docs/ko/reference/predicate/isEqual.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# isEqual

`isEqual` 함수는 두 값이 동일한지 확인하며, `Date`, `RegExp`, 깊은 객체 비교도 지원해요.
두 값이 동일한지 확인해요. `Date`, `RegExp` 같은 깊은 객체 비교도 지원해요.

## 인터페이스

Expand All @@ -10,12 +10,12 @@ function isEqual(a: unknown, b: unknown): boolean;

## 파라미터

- **`a`**: `unknown` - 비교할 첫 번째 값.
- **`b`**: `unknown` - 비교할 두 번째 값.
- `a` (`unknown`): 비교할 첫 번째 값.
- `b` (`unknown`): 비교할 두 번째 값.

## 반환 값

- **`boolean`** - 두 값이 동일하면 `true`, 그렇지 않으면 `false`를 반환해요.
(`boolean`): 두 값이 동일하면 `true`, 그렇지 않으면 `false`를 반환해요.

## 예시

Expand Down
58 changes: 58 additions & 0 deletions docs/ko/reference/predicate/isEqualWith.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# isEqualWith

두 값이 동일한지를 주어진 비교 함수를 이용해서 비교해요.

비교 함수를 제공함으로써 두 값이 동일한지를 검증하는 방법을 세세하게 조정할 수 있어요.
주어진 비교 함수가 `true`를 반환하면, 두 값은 동일하게 취급돼요. `false`를 반환하면, 두 값은 다르게 취급돼요.
`undefined`를 반환하면, [isEqual](./isEqual.md)이 제공하는 기본 방법으로 두 값을 비교해요.

객체, 배열, `Map`, `Set`처럼 여러 요소를 가지고 있을 때도, 주어진 비교 함수로 요소 사이의 값들을 비교해요.

기본적인 비교 방법 위에서, 복잡한 비교를 처리하기 위한 방법을 정의할 수 있어서, 유연하게 두 값을 비교할 수 있어요.

## 인터페이스

```typescript
function isEqualWith(
a: any,
b: any,
areValuesEqual: (
x: any,
y: any,
property?: PropertyKey,
xParent?: any,
yParent?: any,
stack?: Map<any, any>
) => boolean | void
): boolean;
```

### 파라미터

- `a` (`unknown`): 비교할 첫 번째 값.
- `b` (`unknown`): 비교할 두 번째 값.
- `areValuesEqual` (`(x: any, y: any, property?: PropertyKey, xParent?: any, yParent?: any, stack?: Map<any, any>) => boolean | void`): 두 값을 비교하는 방법을 나타내는 비교 함수. 두 값이 같은지를 나타내는 불리언 값을 반환할 수 있어요. `undefined`를 반환하면, 기본 방법으로 두 값을 비교해요.
- `x`: 첫 번째 객체 `a`에 속한 값.
- `y`: 두 번째 객체 `b`에 속한 값.
- `property`: `x``y`를 가져오기 위해 사용한 프로퍼티 키.
- `xParent`: 첫 번째 값 `x`의 부모.
- `yParent`: 두 번째 값 `y`의 부모.
- `stack`: 순환 참조를 처리하기 위한 내부 스택(`Map`).

### 반환 값

(`boolean`): 값이 사용자 지정 기준에 따라 동등하면 `true`를 반환하고, 그렇지 않으면 `false`를 반환합니다.
문자열.

## 예시

```typescript
const customizer = (a, b) => {
if (typeof a === 'string' && typeof b === 'string') {
return a.toLowerCase() === b.toLowerCase();
}
};
isEqualWith('Hello', 'hello', customizer); // true
isEqualWith({ a: 'Hello' }, { a: 'hello' }, customizer); // true
isEqualWith([1, 2, 3], [1, 2, 3], customizer); // true
```
57 changes: 57 additions & 0 deletions docs/reference/predicate/isEqualWith.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# isEqualWith

Compares two values for equality using a custom comparison function.

The custom function allows for fine-tuned control over the comparison process. If it returns a boolean, that result determines the equality. If it returns undefined, the function falls back to the default equality comparison in [isEqual](./isEqual.md).

This function also uses the custom equality function to compare values inside objects,
arrays, `Map`s, `Set`s, and other complex structures, ensuring a deep comparison.

This approach provides flexibility in handling complex comparisons while maintaining efficient default behavior for simpler cases.

## Signature

```typescript
function isEqualWith(
a: any,
b: any,
areValuesEqual: (
x: any,
y: any,
property?: PropertyKey,
xParent?: any,
yParent?: any,
stack?: Map<any, any>
) => boolean | void
): boolean;
```

### Parameters

- `a` (`unknown`): The first value to compare.
- `b` (`unknown`): The second value to compare.
- `areValuesEqual` (`(x: any, y: any, property?: PropertyKey, xParent?: any, yParent?: any, stack?: Map<any, any>) => boolean | void`): A function to customize the comparison. If it returns a boolean, that result will be used. If it returns undefined,
the default equality comparison will be used.
- `x`: The value from the first object `a`.
- `y`: The value from the second object `b`.
- `property`: The property key used to get `x` and `y`.
- `xParent`: The parent of the first value `x`.
- `yParent`: The parent of the second value `y`.
- `stack`: An internal stack (Map) to handle circular references.

### Returns

(`boolean`): `true` if the values are equal according to the customizer, otherwise `false`.

## Examples

```typescript
const customizer = (a, b) => {
if (typeof a === 'string' && typeof b === 'string') {
return a.toLowerCase() === b.toLowerCase();
}
};
isEqualWith('Hello', 'hello', customizer); // true
isEqualWith({ a: 'Hello' }, { a: 'hello' }, customizer); // true
isEqualWith([1, 2, 3], [1, 2, 3], customizer); // true
```
Loading

0 comments on commit 3462a84

Please sign in to comment.