Skip to content

Commit

Permalink
feat(pullAllBy): Implement pullAllBy
Browse files Browse the repository at this point in the history
  • Loading branch information
raon0211 committed Jan 30, 2025
1 parent 2241152 commit bf9aae9
Show file tree
Hide file tree
Showing 8 changed files with 370 additions and 2 deletions.
55 changes: 55 additions & 0 deletions docs/ja/reference/compat/array/pullAllBy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# pullAllBy

::: info
この関数は互換性のために `es-toolkit/compat` からのみインポートできます。代替可能なネイティブ JavaScript API があるか、まだ十分に最適化されていないためです。

`es-toolkit/compat` からこの関数をインポートすると、[lodash と完全に同じように動作](../../../compatibility.md)します。
:::

提供された関数で要素をマッピングした後、配列から指定されたすべての値を削除します。
要素をマッピングする方法はいくつかの方法で指定できます。

- **関数**: 要素を比較する前に、各要素を与えられた関数でマッピングします。各要素に対して関数が実行され、その戻り値で要素を比較します。
- **プロパティ名**: 指定されたプロパティの値で要素を比較します。
- **部分オブジェクト**: 両方の要素が与えられた部分オブジェクトのすべてのプロパティと値に一致するかどうかを基準に比較します。
- **プロパティ-値のペア**: 両方の要素が指定されたプロパティと値に一致するかどうかを基準に比較します。

この関数は`arr`をその場で変更します。
元の配列を変更せずに値を削除したい場合は、[differenceBy](../../array/differenceBy.md)を使用してください。

## インターフェース

```typescript
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: (value: T) => unknown): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: Partial<T>): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: [keyof T, unknown]): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: keyof T): T[];
```

### パラメータ

- `arr` (`T[]`): 変更する配列。
- `valuesToRemove` (`ArrayLike<T>`): 配列から削除する値。
- `getValue`:
- **関数** (`(value: T) => unknown`): 要素を比較する前に、各要素を与えられた関数でマッピングします。各要素に対して関数が実行され、その戻り値で要素を比較します。
- **プロパティ名** (`keyof T`): 指定されたプロパティの値で要素を比較します。
- **部分オブジェクト** (`Partial<T>`): 両方の要素が与えられた部分オブジェクトのすべてのプロパティと値に一致するかどうかを基準に比較します。
- **プロパティ-値のペア** (`[keyof T, unknown]`): 両方の要素が指定されたプロパティと値に一致するかどうかを基準に比較します。

### 戻り値

(`T[]`): 指定された値が削除された修正済み配列。

##

```typescript
// Using a iteratee function
const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], obj => obj.value);
console.log(result); // [{ value: 2 }]

// Using a property name
const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], 'value');
console.log(result); // [{ value: 2 }]
```
4 changes: 2 additions & 2 deletions docs/ko/reference/compat/array/pullAll.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
`es-toolkit/compat`에서 이 함수를 가져오면, [lodash와 완전히 똑같이 동작](../../../compatibility.md)해요.
:::

지정된 모든 값을 배열에서 제거합니다.
지정된 모든 값을 배열에서 제거해요.

이 함수는 `arr`을 제자리에서 변경합니다.
이 함수는 `arr`을 제자리에서 변경해요.
원본 배열을 수정하지 않고 값을 제거하려면 `difference`를 사용하세요.

## 인터페이스
Expand Down
56 changes: 56 additions & 0 deletions docs/ko/reference/compat/array/pullAllBy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# pullAllBy

::: info
이 함수는 호환성을 위한 `es-toolkit/compat` 에서만 가져올 수 있어요. 대체할 수 있는 네이티브 JavaScript API가 있거나, 아직 충분히 최적화되지 않았기 때문이에요.

`es-toolkit/compat`에서 이 함수를 가져오면, [lodash와 완전히 똑같이 동작](../../../compatibility.md)해요.
:::

제공된 함수로 요소들을 매핑한 후, 지정된 모든 값을 배열에서 제거해요.

요소를 매핑하는 방법은 여러 방법으로 명시할 수 있어요.

- **함수**: 요소끼리 비교하기 전, 각각의 요소를 주어진 함수로 매핑해요. 각각의 요소마다 함수가 실행되고, 반환되는 값으로 요소를 비교해요.
- **프로퍼티 이름**: 주어진 프로퍼티의 값으로 요소를 비교해요.
- **부분 객체**: 두 요소 모두가 주어진 부분 객체의 모든 프로퍼티 및 값과 일치하는지를 기준으로 비교해요.
- **프로퍼티-값 쌍**: 두 요소 모두가 주어진 프로퍼티 및 값과 일치하는지를 기준으로 비교해요.

이 함수는 `arr`을 제자리에서 변경해요.
원본 배열을 수정하지 않고 값을 제거하려면 [differenceBy](../../array/differenceBy.md)를 사용하세요.

## 인터페이스

```typescript
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: (value: T) => unknown): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: Partial<T>): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: [keyof T, unknown]): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: keyof T): T[];
```

### 파라미터

- `arr` (`T[]`): 수정할 배열.
- `valuesToRemove` (`ArrayLike<T>`): 배열에서 제거할 값.
- `getValue`:
- **함수** (`(value: T) => unknown`): 요소끼리 비교하기 전, 각각의 요소를 주어진 함수로 매핑해요. 각각의 요소마다 함수가 실행되고, 반환되는 값으로 요소를 비교해요.
- **프로퍼티 이름** (`keyof T`): 주어진 프로퍼티의 값으로 요소를 비교해요.
- **부분 객체** (`Partial<T>`): 두 요소 모두가 주어진 부분 객체의 모든 프로퍼티 및 값과 일치하는지를 기준으로 비교해요.
- **프로퍼티-값 쌍** (`[keyof T, unknown]`): 두 요소 모두가 주어진 프로퍼티 및 값과 일치하는지를 기준으로 비교해요.

### 반환 값

(`T[]`): 지정된 값이 제거된 수정된 배열.

## 예시

```typescript
// Using a iteratee function
const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], obj => obj.value);
console.log(result); // [{ value: 2 }]

// Using a property name
const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], 'value');
console.log(result); // [{ value: 2 }]
```
56 changes: 56 additions & 0 deletions docs/reference/compat/array/pullAllBy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# pullAllBy

::: info
This function is only available in `es-toolkit/compat` for compatibility reasons. It either has alternative native JavaScript APIs or isn’t fully optimized yet.

When imported from `es-toolkit/compat`, it behaves exactly like lodash and provides the same functionalities, as detailed [here](../../../compatibility.md).
:::

Removes all specified values from an array after mapping their elements through a provided function.

You can specify the mapper function in several ways:

- **Iteratee function**: If you provide a function, it will be used to map each element before comparison. The function will be called with each element and should return a value to use for comparison.
- **Property name**: If you provide a property name (string, symbol, or number), elements will be compared based on the value of that property.
- **Partial object**: If you provide a partial object, elements will be compared based on whether they match all the properties and values in that object.
- **Property-value pair**: If you provide a tuple of [property, value], elements will be compared based on whether the specified property matches the given value.

This function changes `arr` in place.
If you want to remove values without modifying the original array, use [differenceBy](../../array/differenceBy.md).

## Signature

```typescript
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: (value: T) => unknown): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: Partial<T>): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: [keyof T, unknown]): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: keyof T): T[];
```

### Parameters

- `arr` (`T[]`): The array to modify.
- `valuesToRemove` (`ArrayLike<T>`): The values to remove from the array.
- `getValue`:
- **Iteratee function** (`(value: T) => unknown`): If you provide a function, it will be used to map each element before comparison. The function will be called with each element and should return a value to use for comparison.
- **Property name** (`keyof T`): If you provide a property name (string, symbol, or number), elements will be compared based on the value of that property.
- **Partial object** (`Partial<T>`): If you provide a partial object, elements will be compared based on whether they match all the properties and values in that object.
- **Property-value pair** (`[keyof T, unknown]`): If you provide a tuple of [property, value], elements will be compared based on whether the specified property matches the given value.

### Returns

(`T[]`): The modified array with the specified values removed.

## Examples

```typescript
// Using a iteratee function
const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], obj => obj.value);
console.log(result); // [{ value: 2 }]

// Using a property name
const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], 'value');
console.log(result); // [{ value: 2 }]
```
55 changes: 55 additions & 0 deletions docs/zh_hans/reference/compat/array/pullAllBy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# pullAllBy

::: info
出于兼容性原因,此函数仅在 `es-toolkit/compat` 中提供。它可能具有替代的原生 JavaScript API,或者尚未完全优化。

`es-toolkit/compat` 导入时,它的行为与 lodash 完全一致,并提供相同的功能,详情请见 [这里](../../../compatibility.md)
:::

在通过提供的函数映射元素后,从数组中移除所有指定的值。
你可以使用以下几种方式来映射元素:

- **函数**: 在比较元素之前,使用给定函数映射每个元素。函数会对每个元素执行,并使用返回值进行比较。
- **属性名**: 使用指定属性的值来比较元素。
- **部分对象**: 根据两个元素是否都匹配给定部分对象的所有属性和值来比较。
- **属性-值对**: 根据两个元素是否都匹配指定的属性和值来比较。

此函数会直接修改 `arr`
如果你想在不修改原始数组的情况下移除值,请使用 [differenceBy](../../array/differenceBy.md)

## 签名

```typescript
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: (value: T) => unknown): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: Partial<T>): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: [keyof T, unknown]): T[];
function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: keyof T): T[];
```

### 参数

- `arr` (`T[]`): 要修改的数组。
- `valuesToRemove` (`ArrayLike<T>`): 要从数组中移除的值。
- `getValue`:
- **函数** (`(value: T) => unknown`): 在比较元素之前,使用给定函数映射每个元素。函数会对每个元素执行,并使用返回值进行比较。
- **属性名** (`keyof T`): 使用指定属性的值来比较元素。
- **部分对象** (`Partial<T>`): 根据两个元素是否都匹配给定部分对象的所有属性和值来比较。
- **属性-值对** (`[keyof T, unknown]`): 根据两个元素是否都匹配指定的属性和值来比较。

### 返回值

(`T[]`): 移除指定值后的修改数组。

## 示例

```typescript
// Using a iteratee function
const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], obj => obj.value);
console.log(result); // [{ value: 2 }]

// Using a property name
const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], 'value');
console.log(result); // [{ value: 2 }]
```
24 changes: 24 additions & 0 deletions src/compat/array/pullAllBy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, expect, it } from 'vitest';
import { pullAllBy } from './pullAllBy';

describe('pullAllBy', () => {
it('should accept an `iteratee`', () => {
const array = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }];

const actual = pullAllBy(array, [{ x: 1 }, { x: 3 }], object => object.x);

expect(actual).toEqual([{ x: 2 }]);
});

it('should provide correct `iteratee` arguments', () => {
let args: any;
const array = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }];

pullAllBy(array, [{ x: 1 }, { x: 3 }], function () {
// eslint-disable-next-line
args || (args = Array.prototype.slice.call(arguments));
});

expect(args).toEqual([{ x: 1 }]);
});
});
121 changes: 121 additions & 0 deletions src/compat/array/pullAllBy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { iteratee } from '../util/iteratee';

/**
* Removes all specified values from an array using an iteratee function.
*
* This function changes `arr` in place.
* If you want to remove values without modifying the original array, use `differenceBy`.
*
* @template T
* @param {T[]} arr - The array to modify.
* @param {ArrayLike<T>} valuesToRemove - The values to remove from the array.
* @param {(value: T) => unknown} getValue - The iteratee invoked per element.
* @returns {T[]} The modified array with the specified values removed.
*
* @example
* const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
* const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], obj => obj.value);
* console.log(result); // [{ value: 2 }]
*/
export function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: (value: T) => unknown): T[];

/**
* Removes all specified values from an array using an iteratee function.
*
* This function changes `arr` in place.
* If you want to remove values without modifying the original array, use `differenceBy`.
*
* @template T
* @param {T[]} arr - The array to modify.
* @param {ArrayLike<T>} valuesToRemove - The values to remove from the array.
* @param {Partial<T>} getValue - The partial object to match against each element.
* @returns {T[]} The modified array with the specified values removed.
*/
export function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: Partial<T>): T[];

/**
* Removes all specified values from an array using an iteratee function.
*
* This function changes `arr` in place.
* If you want to remove values without modifying the original array, use `differenceBy`.
*
* @template T
* @param {T[]} arr - The array to modify.
* @param {ArrayLike<T>} valuesToRemove - The values to remove from the array.
* @param {[keyof T, unknown]} getValue - The property-value pair to match against each element.
* @returns {T[]} The modified array with the specified values removed.
*/
export function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: [keyof T, unknown]): T[];

/**
* Removes all specified values from an array using an iteratee function.
*
* This function changes `arr` in place.
* If you want to remove values without modifying the original array, use `differenceBy`.
*
* @template T
* @param {T[]} arr - The array to modify.
* @param {ArrayLike<T>} valuesToRemove - The values to remove from the array.
* @param {keyof T} getValue - The key of the property to match against each element.
* @returns {T[]} The modified array with the specified values removed.
*
* @example
* const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
* const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], 'value');
* console.log(result); // [{ value: 2 }]
*/
export function pullAllBy<T>(arr: T[], valuesToRemove: ArrayLike<T>, getValue: keyof T): T[];

/**
* Removes all specified values from an array using an iteratee function.
*
* This function changes `arr` in place.
* If you want to remove values without modifying the original array, use `differenceBy`.
*
* @template T
* @param {T[]} arr - The array to modify.
* @param {ArrayLike<T>} valuesToRemove - The values to remove from the array.
* @param {keyof T} getValue - The key of the property to match against each element.
* @returns {T[]} The modified array with the specified values removed.
*
* @example
* // Using a iteratee function
* const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
* const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], obj => obj.value);
* console.log(result); // [{ value: 2 }]
*
* // Using a property name
* const items = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 1 }];
* const result = pullAllBy(items, [{ value: 1 }, { value: 3 }], 'value');
* console.log(result); // [{ value: 2 }]
*/
export function pullAllBy<T>(
arr: T[],
valuesToRemove: ArrayLike<T>,
_getValue: ((value: T, index: number, arr: ArrayLike<T>) => boolean) | Partial<T> | [keyof T, unknown] | keyof T
): T[] {
const getValue = iteratee(_getValue);
const valuesSet = new Set(Array.from(valuesToRemove).map(x => getValue(x)));

let resultIndex = 0;

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

if (valuesSet.has(value)) {
continue;
}

// For handling sparse arrays
if (!Object.hasOwn(arr, i)) {
delete arr[resultIndex++];
continue;
}

arr[resultIndex++] = arr[i];
}

arr.length = resultIndex;

return arr;
}
1 change: 1 addition & 0 deletions src/compat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export { nth } from './array/nth.ts';
export { orderBy } from './array/orderBy.ts';
export { pull } from './array/pull.ts';
export { pullAll } from './array/pullAll.ts';
export { pullAllBy } from './array/pullAllBy.ts';
export { remove } from './array/remove.ts';
export { reverse } from './array/reverse.ts';
export { sample } from './array/sample.ts';
Expand Down

0 comments on commit bf9aae9

Please sign in to comment.