diff --git a/docs/ja/reference/compat/array/pullAllBy.md b/docs/ja/reference/compat/array/pullAllBy.md new file mode 100644 index 000000000..00d8d69b6 --- /dev/null +++ b/docs/ja/reference/compat/array/pullAllBy.md @@ -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(arr: T[], valuesToRemove: ArrayLike, getValue: (value: T) => unknown): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: Partial): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: [keyof T, unknown]): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: keyof T): T[]; +``` + +### パラメータ + +- `arr` (`T[]`): 変更する配列。 +- `valuesToRemove` (`ArrayLike`): 配列から削除する値。 +- `getValue`: + - **関数** (`(value: T) => unknown`): 要素を比較する前に、各要素を与えられた関数でマッピングします。各要素に対して関数が実行され、その戻り値で要素を比較します。 + - **プロパティ名** (`keyof T`): 指定されたプロパティの値で要素を比較します。 + - **部分オブジェクト** (`Partial`): 両方の要素が与えられた部分オブジェクトのすべてのプロパティと値に一致するかどうかを基準に比較します。 + - **プロパティ-値のペア** (`[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 }] +``` diff --git a/docs/ko/reference/compat/array/pullAll.md b/docs/ko/reference/compat/array/pullAll.md index 1d6e0ccea..c8a66eecf 100644 --- a/docs/ko/reference/compat/array/pullAll.md +++ b/docs/ko/reference/compat/array/pullAll.md @@ -6,9 +6,9 @@ `es-toolkit/compat`에서 이 함수를 가져오면, [lodash와 완전히 똑같이 동작](../../../compatibility.md)해요. ::: -지정된 모든 값을 배열에서 제거합니다. +지정된 모든 값을 배열에서 제거해요. -이 함수는 `arr`을 제자리에서 변경합니다. +이 함수는 `arr`을 제자리에서 변경해요. 원본 배열을 수정하지 않고 값을 제거하려면 `difference`를 사용하세요. ## 인터페이스 diff --git a/docs/ko/reference/compat/array/pullAllBy.md b/docs/ko/reference/compat/array/pullAllBy.md new file mode 100644 index 000000000..3d343efc7 --- /dev/null +++ b/docs/ko/reference/compat/array/pullAllBy.md @@ -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(arr: T[], valuesToRemove: ArrayLike, getValue: (value: T) => unknown): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: Partial): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: [keyof T, unknown]): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: keyof T): T[]; +``` + +### 파라미터 + +- `arr` (`T[]`): 수정할 배열. +- `valuesToRemove` (`ArrayLike`): 배열에서 제거할 값. +- `getValue`: + - **함수** (`(value: T) => unknown`): 요소끼리 비교하기 전, 각각의 요소를 주어진 함수로 매핑해요. 각각의 요소마다 함수가 실행되고, 반환되는 값으로 요소를 비교해요. + - **프로퍼티 이름** (`keyof T`): 주어진 프로퍼티의 값으로 요소를 비교해요. + - **부분 객체** (`Partial`): 두 요소 모두가 주어진 부분 객체의 모든 프로퍼티 및 값과 일치하는지를 기준으로 비교해요. + - **프로퍼티-값 쌍** (`[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 }] +``` diff --git a/docs/reference/compat/array/pullAllBy.md b/docs/reference/compat/array/pullAllBy.md new file mode 100644 index 000000000..b95f53b45 --- /dev/null +++ b/docs/reference/compat/array/pullAllBy.md @@ -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(arr: T[], valuesToRemove: ArrayLike, getValue: (value: T) => unknown): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: Partial): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: [keyof T, unknown]): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: keyof T): T[]; +``` + +### Parameters + +- `arr` (`T[]`): The array to modify. +- `valuesToRemove` (`ArrayLike`): 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`): 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 }] +``` diff --git a/docs/zh_hans/reference/compat/array/pullAllBy.md b/docs/zh_hans/reference/compat/array/pullAllBy.md new file mode 100644 index 000000000..f8bd940b3 --- /dev/null +++ b/docs/zh_hans/reference/compat/array/pullAllBy.md @@ -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(arr: T[], valuesToRemove: ArrayLike, getValue: (value: T) => unknown): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: Partial): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: [keyof T, unknown]): T[]; +function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: keyof T): T[]; +``` + +### 参数 + +- `arr` (`T[]`): 要修改的数组。 +- `valuesToRemove` (`ArrayLike`): 要从数组中移除的值。 +- `getValue`: + - **函数** (`(value: T) => unknown`): 在比较元素之前,使用给定函数映射每个元素。函数会对每个元素执行,并使用返回值进行比较。 + - **属性名** (`keyof T`): 使用指定属性的值来比较元素。 + - **部分对象** (`Partial`): 根据两个元素是否都匹配给定部分对象的所有属性和值来比较。 + - **属性-值对** (`[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 }] +``` diff --git a/src/compat/array/pullAllBy.spec.ts b/src/compat/array/pullAllBy.spec.ts new file mode 100644 index 000000000..c9d09310a --- /dev/null +++ b/src/compat/array/pullAllBy.spec.ts @@ -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 }]); + }); +}); diff --git a/src/compat/array/pullAllBy.ts b/src/compat/array/pullAllBy.ts new file mode 100644 index 000000000..f2ba34992 --- /dev/null +++ b/src/compat/array/pullAllBy.ts @@ -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} 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(arr: T[], valuesToRemove: ArrayLike, 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} valuesToRemove - The values to remove from the array. + * @param {Partial} getValue - The partial object to match against each element. + * @returns {T[]} The modified array with the specified values removed. + */ +export function pullAllBy(arr: T[], valuesToRemove: ArrayLike, getValue: Partial): 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} 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(arr: T[], valuesToRemove: ArrayLike, 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} 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(arr: T[], valuesToRemove: ArrayLike, 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} 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( + arr: T[], + valuesToRemove: ArrayLike, + _getValue: ((value: T, index: number, arr: ArrayLike) => boolean) | Partial | [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; +} diff --git a/src/compat/index.ts b/src/compat/index.ts index 7977569ea..54543f65c 100644 --- a/src/compat/index.ts +++ b/src/compat/index.ts @@ -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';