Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(differenceBy): add differenceBy in compat #487

Closed
wants to merge 8 commits into from
Closed
6 changes: 6 additions & 0 deletions benchmarks/performance/differenceBy.bench.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { bench, describe } from 'vitest';
import { differenceBy as differenceByToolkit_ } from 'es-toolkit';
import { differenceBy as differenceByCompatToolkit_ } from 'es-toolkit/compat';
import { differenceBy as differenceByLodash_ } from 'lodash';

const differenceByToolkit = differenceByToolkit_;
const differenceByCompatToolkit = differenceByCompatToolkit_;
const differenceByLodash = differenceByLodash_;

describe('differenceBy', () => {
bench('es-toolkit/differenceBy', () => {
differenceByToolkit([1.2, 2.3, 3.4], [1.2], Math.floor);
});

bench('es-toolkit/compat/differenceBy', () => {
differenceByCompatToolkit([1.2, 2.3, 3.4], [1.2], Math.floor);
});

bench('lodash/differenceBy', () => {
differenceByLodash([1.2, 2.3, 3.4], [1.2], Math.floor);
});
Expand Down
16 changes: 16 additions & 0 deletions docs/ja/reference/array/differenceBy.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,19 @@ const mapper = item => item.id;
const result = differenceBy(array1, array2, mapper);
// resultは[{ id: 1 }, { id: 3 }, { id: 5 }]になります。idが2の要素は両方の配列に存在するため、結果から除外されます。
```

## Lodash 互換性

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

- `differenceBy` は最初の配列のようなオブジェクトを1つ以上の後続の配列のようなオブジェクトと比較します。
- `differenceBy` はオプションとして、最後の引数に関数またはプロパティキーを受け取ることができます。

```typescript
import { differenceBy } from 'es-toolkit/compat';

differenceBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], item => item.x); // Returns [{ x: 2 }]
differenceBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], 'x'); // Returns [{ x: 2 }]
differenceBy([{ x: 1 }, { x: 2 }, { x: 3 }], [{ x: 2 }], [{ x: 3 }], 'x'); // Returns [{ x: 1 }]
differenceBy([1, 2, 3], [2], [3]); // Returns [1]
```
16 changes: 16 additions & 0 deletions docs/ko/reference/array/differenceBy.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,19 @@ const mapper = item => item.id;
const result = differenceBy(array1, array2, mapper);
// result는 [{ id: 1 }, { id: 3 }, { id: 5 }]가 돼요. id가 2인 요소들은 두 배열 모두에 있어서 결과에서 제외돼요.
```

## Lodash 호환성

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

- `differenceBy`는 첫 번째 유사 배열 객체와 하나 이상의 후속 유사 배열 객체를 비교해요.
- `differenceBy`는 선택적으로 마지막 인자로 함수 또는 속성 키를 받아요.

```typescript
import { differenceBy } from 'es-toolkit/compat';

differenceBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], item => item.x); // Returns [{ x: 2 }]
differenceBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], 'x'); // Returns [{ x: 2 }]
differenceBy([{ x: 1 }, { x: 2 }, { x: 3 }], [{ x: 2 }], [{ x: 3 }], 'x'); // Returns [{ x: 1 }]
differenceBy([1, 2, 3], [2], [3]); // Returns [1]
```
16 changes: 16 additions & 0 deletions docs/reference/array/differenceBy.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,19 @@ const mapper = item => item.id;
const result = differenceBy(array1, array2, mapper);
// result will be [{ id: 1 }, { id: 3 }, { id: 5 }] since the elements with id 2 are in both arrays and are excluded from the result.
```

## Lodash Compatibility

Import `differenceBy` from `es-toolkit/compat` for full compatibility with lodash.

- `differenceBy` compares the first array-like object to one or more subsequent array-like objects.
- `differenceBy` can optionally accept an iteratee as the last argument, which can either be a function or a property key.

```typescript
import { differenceBy } from 'es-toolkit/compat';

differenceBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], item => item.x); // Returns [{ x: 2 }]
differenceBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], 'x'); // Returns [{ x: 2 }]
differenceBy([{ x: 1 }, { x: 2 }, { x: 3 }], [{ x: 2 }], [{ x: 3 }], 'x'); // Returns [{ x: 1 }]
differenceBy([1, 2, 3], [2], [3]); // Returns [1]
```
16 changes: 16 additions & 0 deletions docs/zh_hans/reference/array/differenceBy.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,19 @@ const mapper = item => item.id;
const result = differenceBy(array1, array2, mapper);
// 结果将是 [{ id: 1 }, { id: 3 }, { id: 5 }] 因为具有 id 为 2 的元素在两个数组中都存在,所以它们被排除在结果之外。
```

## Lodash 兼容性

从 `es-toolkit/compat` 中导入 `differenceBy` 以实现与 lodash 的完全兼容。

- `differenceBy` 将第一个类数组对象与一个或多个后续类数组对象进行比较。
- `differenceBy` 可以选择性地接受一个迭代器作为最后一个参数,该迭代器可以是函数或属性键。

```typescript
import { differenceBy } from 'es-toolkit/compat';

differenceBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], item => item.x); // Returns [{ x: 2 }]
differenceBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], 'x'); // Returns [{ x: 2 }]
differenceBy([{ x: 1 }, { x: 2 }, { x: 3 }], [{ x: 2 }], [{ x: 3 }], 'x'); // Returns [{ x: 1 }]
differenceBy([1, 2, 3], [2], [3]); // Returns [1]
```
101 changes: 101 additions & 0 deletions src/compat/array/differenceBy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { describe, expect, it } from 'vitest';
import { LARGE_ARRAY_SIZE } from '../_internal/LARGE_ARRAY_SIZE';
import { range } from '../../math/range';
import { differenceBy } from './differenceBy';
import { slice } from '../_internal/slice';

/**
* @see https://github.com/lodash/lodash/blob/6a2cc1dfcf7634fea70d1bc5bd22db453df67b42/test/difference-methods.spec.js#L1
*/
describe('difference', () => {
it(`should return the difference of two arrays`, () => {
const actual = differenceBy([2, 1], [2, 3]);
expect(actual).toEqual([1]);
});

it(`should return the difference of multiple arrays`, () => {
const actual = differenceBy([2, 1, 2, 3], [3, 4], [3, 2]);
expect(actual).toEqual([1]);
});

it(`should treat \`-0\` as \`0\``, () => {
const array = [-0, 0];

const actual = array.map(value => differenceBy(array, [value]));

expect(actual).toEqual([[], []]);

expect(differenceBy([-0, 1], [1])).toEqual([-0]);
});

it(`should match \`NaN\``, () => {
expect(differenceBy([1, NaN, 3], [NaN, 5, NaN])).toEqual([1, 3]);
});

it(`should work with large arrays`, () => {
const array1: unknown[] = range(LARGE_ARRAY_SIZE + 1);
const array2: unknown[] = range(LARGE_ARRAY_SIZE);

const a = {};
const b = {};
const c = {};

array1.push(a, b, c);
array2.push(b, c, a);

expect(differenceBy(array1, array2)).toEqual([LARGE_ARRAY_SIZE]);
});

it(`should work with large arrays of \`-0\` as \`0\``, () => {
const array = [-0, 0];

const actual = array.map(value => {
const largeArray = Array.from({ length: LARGE_ARRAY_SIZE }).map(() => value);

return differenceBy(array, largeArray);
});

expect(actual).toEqual([[], []]);

const largeArray = Array.from({ length: LARGE_ARRAY_SIZE }).map(() => 1);
expect(differenceBy([-0, 1], largeArray)).toEqual([-0]);
});

it(`should work with large arrays of \`NaN\``, () => {
const largeArray = Array.from({ length: LARGE_ARRAY_SIZE }).map(() => NaN);
expect(differenceBy([1, NaN, 3], largeArray)).toEqual([1, 3]);
});

it(`should work with large arrays of objects`, () => {
const object1 = {};
const object2 = {};
const largeArray = Array.from({ length: LARGE_ARRAY_SIZE }).map(() => ({}));

expect(differenceBy([object1, object2], largeArray)).toEqual([object1, object2]);
});
});

/**
* @see https://github.com/lodash/lodash/blob/6a2cc1dfcf7634fea70d1bc5bd22db453df67b42/src/differenceBy.ts#L1
*/
describe('differenceBy', () => {
it('should accept an `iteratee`', () => {
const actual1 = differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
expect(actual1).toEqual([1.2]);

expect(differenceBy([1, 2, 3, 4, 5, 6], [1], [2], [3], [4, 5], value => value)).toEqual([6]);

const actual2 = differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], 'x');
expect(actual2).toEqual([{ x: 2 }]);
});

it('should provide correct `iteratee` arguments', () => {
let args: number[] | undefined;

differenceBy([2.1, 1.2], [2.3, 3.4], function () {
args || (args = slice.call(arguments));
});

expect(args).toEqual([2.3]);
});
});
Loading