From 84e917a1de6b7f1c881ae3dc3c85b6ba775cb03a Mon Sep 17 00:00:00 2001 From: DevGon Date: Tue, 2 Jul 2024 23:57:30 +0900 Subject: [PATCH 1/8] feat(without): Add `without` function --- src/array/index.ts | 1 + src/array/without.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/array/without.ts diff --git a/src/array/index.ts b/src/array/index.ts index 7469ca9f5..e69de8f20 100644 --- a/src/array/index.ts +++ b/src/array/index.ts @@ -28,6 +28,7 @@ export { unionWith } from './unionWith.ts'; export { uniq } from './uniq.ts'; export { uniqBy } from './uniqBy.ts'; export { uniqWith } from './uniqWith.ts'; +export { without } from './without.ts'; export { xor } from './xor.ts'; export { xorBy } from './xorBy.ts'; export { xorWith } from './xorWith.ts'; diff --git a/src/array/without.ts b/src/array/without.ts new file mode 100644 index 000000000..dcbb1e4c7 --- /dev/null +++ b/src/array/without.ts @@ -0,0 +1,29 @@ +/** + * Creates an array excluding all given values using SameValueZero for equality comparisons. + * + * This function takes an input array and returns a new array that excludes all values + * specified in the second argument. It uses SameValueZero for equality comparisons, + * meaning that it considers -0 and +0 as equal but treats NaN as unequal to itself. + * + * @template T The type of elements in the array. + * @param {ArrayLike} array - The array to filter. + * @param {...T[]} values - The values to exclude. + * @returns {T[]} A new array without the specified values. + * + * @example + * // Removes the specified values from the array + * without([1, 2, 3, 4, 5], 2, 4); + * // Returns: [1, 3, 5] + * + * @example + * // Removes specified string values from the array + * without(['a', 'b', 'c', 'a'], 'a'); + * // Returns: ['b', 'c'] + */ +export function without(array: ArrayLike, ...values: T[]): T[] { + if (!array || typeof array.length !== 'number') { + return []; + } + const valuesSet = new Set(values); + return Array.prototype.filter.call(array, item => !valuesSet.has(item)); +} From ea30a0f9dab45c9656c376b86653699598c788cf Mon Sep 17 00:00:00 2001 From: DevGon Date: Tue, 2 Jul 2024 23:58:19 +0900 Subject: [PATCH 2/8] feat(without): Add `without` function test code --- src/array/without.spec.ts | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/array/without.spec.ts diff --git a/src/array/without.spec.ts b/src/array/without.spec.ts new file mode 100644 index 000000000..78a7d9244 --- /dev/null +++ b/src/array/without.spec.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from 'vitest'; +import { without } from './without'; + +describe('without', () => { + it('should return an empty array when the input array is empty', () => { + expect(without([], 1, 2, 3)).toEqual([]); + }); + + it('should return the same array when no values are provided to exclude', () => { + expect(without([1, 2, 3])).toEqual([1, 2, 3]); + }); + + it('should return a new array excluding the specified values', () => { + expect(without([1, 2, 3, 4, 5], 2, 4)).toEqual([1, 3, 5]); + expect(without(['a', 'b', 'c', 'a'], 'a')).toEqual(['b', 'c']); + }); + + it('should handle cases where none of the specified values are in the array', () => { + expect(without([1, 2, 3], 4, 5)).toEqual([1, 2, 3]); + }); + + it('should handle cases with different types of values', () => { + expect(without([1, '2', 3, '4'], 2, '4')).toEqual([1, '2', 3]); + expect(without([1, '1', 2, '2'], 1, '2')).toEqual(['1', 2]); + }); + + it('should return an empty array when input is not a valid array', () => { + expect(without(null as any, 1, 2)).toEqual([]); + expect(without(undefined as any, 1, 2)).toEqual([]); + expect(without({ length: 'invalid' } as any, 1, 2)).toEqual([]); + }); + + it('should handle NaN values correctly', () => { + expect(without([NaN, 1, 2, NaN, 3], NaN)).toEqual([1, 2, 3]); + }); + + it('should treat +0 and -0 as equal', () => { + expect(without([0, -0, 1, 2], 0)).toEqual([1, 2]); + expect(without([0, -0, 1, 2], -0)).toEqual([1, 2]); + }); +}); From 4222ce48c2012b0c82fc2d855b5280db40f4098e Mon Sep 17 00:00:00 2001 From: DevGon Date: Wed, 3 Jul 2024 00:00:48 +0900 Subject: [PATCH 3/8] feat(without): Add `without` function docs --- docs/ko/reference/array/without.md | 46 ++++++++++++++++++++++++++++ docs/reference/array/without.md | 48 ++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 docs/ko/reference/array/without.md create mode 100644 docs/reference/array/without.md diff --git a/docs/ko/reference/array/without.md b/docs/ko/reference/array/without.md new file mode 100644 index 000000000..6c6501845 --- /dev/null +++ b/docs/ko/reference/array/without.md @@ -0,0 +1,46 @@ +# without + +SameValueZero 동등성 비교를 사용하여 주어진 값들을 제외한 배열을 생성합니다. + +이 함수는 입력 배열을 받아 추가 인수로 지정된 모든 값을 제외한 새 배열을 반환합니다. SameValueZero 동등성 비교를 사용하여 -0과 +0을 동일하게 간주하지만 NaN은 자기 자신과 다르게 간주합니다. + +## 인터페이스 + +```typescript +function without(array: ArrayLike, ...values: T[]): T[]; +``` + +### 파라미터 + +- `array` (`ArrayLike`): 필터링할 배열. +- `values` (`...T[]`): 제외할 값들. + +### 반환 값 + +(`T[]`) 지정된 값을 제외한 새 배열. + +### 에러 + +명시적으로 예외를 발생시키지는 않지만, 입력이 유효한 배열이 아니거나 배열 길이가 유효하지 않은 경우 빈 배열을 반환합니다. + +## Examples + +```typescript +import { without } from 'es-toolkit/array'; + +// 배열에서 지정된 값을 제거합니다 +without([1, 2, 3, 4, 5], 2, 4); +// 반환: [1, 3, 5] + +// 배열에서 지정된 문자열 값을 제거합니다 +without(['a', 'b', 'c', 'a'], 'a'); +// 반환: ['b', 'c'] + +// 지정된 값이 배열에 없는 경우를 처리합니다 +without([1, 2, 3], 4, 5); +// 반환: [1, 2, 3] + +// 다른 유형의 값을 포함한 경우를 처리합니다 +without([1, '2', 3, '4'], 2, '4'); +// 반환: [1, '2', 3] +``` diff --git a/docs/reference/array/without.md b/docs/reference/array/without.md new file mode 100644 index 000000000..7fb28cc01 --- /dev/null +++ b/docs/reference/array/without.md @@ -0,0 +1,48 @@ +# without + +Creates an array excluding all given values using SameValueZero for equality comparisons. + +This function takes an input array and returns a new array that excludes all values +specified in the additional arguments. It uses SameValueZero for equality comparisons, +meaning that it considers -0 and +0 as equal but treats NaN as unequal to itself. + +## Signature + +```typescript +function without(array: ArrayLike, ...values: T[]): T[]; +``` + +### Parameters + +- `array` (`ArrayLike`): The array to filter. +- `values` (`...T[]`): The values to exclude. + +### Returns + +(`T[]`) A new array without the specified values. + +### Throws + +Does not throw explicitly but returns an empty array if the input is not a valid array or has invalid array length. + +## Examples + +```typescript +import { without } from 'es-toolkit/array'; + +// Removes the specified values from the array +without([1, 2, 3, 4, 5], 2, 4); +// Returns: [1, 3, 5] + +// Removes specified string values from the array +without(['a', 'b', 'c', 'a'], 'a'); +// Returns: ['b', 'c'] + +// Handles cases where none of the specified values are in the array +without([1, 2, 3], 4, 5); +// Returns: [1, 2, 3] + +// Handles cases with different types of values +without([1, '2', 3, '4'], 2, '4'); +// Returns: [1, '2', 3] +``` From 44086d27d64e370c57398b081edfd445c7e5ffd6 Mon Sep 17 00:00:00 2001 From: DevGon Date: Wed, 3 Jul 2024 00:01:04 +0900 Subject: [PATCH 4/8] feat(without): Add `without` function bench --- benchmarks/without.bench.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 benchmarks/without.bench.ts diff --git a/benchmarks/without.bench.ts b/benchmarks/without.bench.ts new file mode 100644 index 000000000..f8cbd26f0 --- /dev/null +++ b/benchmarks/without.bench.ts @@ -0,0 +1,31 @@ +import { bench, describe } from 'vitest'; +import { without as withoutEsToolkit } from 'es-toolkit'; +import { without as withoutLodash } from 'lodash'; + +const generateArray = (length: number, max: number) => Array.from({ length }, () => Math.floor(Math.random() * max)); + +describe('without, small arrays', () => { + const array = [1, 2, 3, 4, 5]; + const values = [2, 4]; + + bench('es-toolkit/without', () => { + withoutEsToolkit(array, ...values); + }); + + bench('lodash/without', () => { + withoutLodash(array, ...values); + }); +}); + +describe('without, large arrays', () => { + const array = generateArray(10000, 1000); + const values = generateArray(100, 1000); + + bench('es-toolkit/without', () => { + withoutEsToolkit(array, ...values); + }); + + bench('lodash/without', () => { + withoutLodash(array, ...values); + }); +}); From 6e972f079cad9ed069d133b130090f900dd9a1cd Mon Sep 17 00:00:00 2001 From: Sojin Park Date: Wed, 3 Jul 2024 09:47:08 +0900 Subject: [PATCH 5/8] Update docs/ko/reference/array/without.md --- docs/ko/reference/array/without.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ko/reference/array/without.md b/docs/ko/reference/array/without.md index 6c6501845..afb48bfdf 100644 --- a/docs/ko/reference/array/without.md +++ b/docs/ko/reference/array/without.md @@ -1,8 +1,8 @@ # without -SameValueZero 동등성 비교를 사용하여 주어진 값들을 제외한 배열을 생성합니다. +배열에서 주어진 값을 제거한 새로운 배열을 만들어요. -이 함수는 입력 배열을 받아 추가 인수로 지정된 모든 값을 제외한 새 배열을 반환합니다. SameValueZero 동등성 비교를 사용하여 -0과 +0을 동일하게 간주하지만 NaN은 자기 자신과 다르게 간주합니다. +값이 같은지는 [SameValueZero](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero) 기준으로 비교하기 때문에, `NaN`과도 사용할 수 있어요. ## 인터페이스 From 32cfc659f8df1d26bf0420a3a04a78aea496454d Mon Sep 17 00:00:00 2001 From: Sojin Park Date: Wed, 3 Jul 2024 09:58:06 +0900 Subject: [PATCH 6/8] Apply suggestions from code review --- docs/ko/reference/array/without.md | 20 ++++++++------------ docs/reference/array/without.md | 14 ++++---------- src/array/without.ts | 13 ++++--------- 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/docs/ko/reference/array/without.md b/docs/ko/reference/array/without.md index afb48bfdf..9916b5bc1 100644 --- a/docs/ko/reference/array/without.md +++ b/docs/ko/reference/array/without.md @@ -7,21 +7,17 @@ ## 인터페이스 ```typescript -function without(array: ArrayLike, ...values: T[]): T[]; +function without(array: T[], ...values: T[]): T[]; ``` ### 파라미터 -- `array` (`ArrayLike`): 필터링할 배열. -- `values` (`...T[]`): 제외할 값들. +- `array` (`T[]`): 값을 제거할 배열. +- `values` (`...T[]`): 제거할 값. ### 반환 값 -(`T[]`) 지정된 값을 제외한 새 배열. - -### 에러 - -명시적으로 예외를 발생시키지는 않지만, 입력이 유효한 배열이 아니거나 배열 길이가 유효하지 않은 경우 빈 배열을 반환합니다. +(`T[]`) 주어진 값을 제외한 새 배열. ## Examples @@ -30,17 +26,17 @@ import { without } from 'es-toolkit/array'; // 배열에서 지정된 값을 제거합니다 without([1, 2, 3, 4, 5], 2, 4); -// 반환: [1, 3, 5] +// 결과 값: [1, 3, 5] // 배열에서 지정된 문자열 값을 제거합니다 without(['a', 'b', 'c', 'a'], 'a'); -// 반환: ['b', 'c'] +// 결과 값: ['b', 'c'] // 지정된 값이 배열에 없는 경우를 처리합니다 without([1, 2, 3], 4, 5); -// 반환: [1, 2, 3] +// 결과 값: [1, 2, 3] // 다른 유형의 값을 포함한 경우를 처리합니다 without([1, '2', 3, '4'], 2, '4'); -// 반환: [1, '2', 3] +// 결과 값: [1, '2', 3] ``` diff --git a/docs/reference/array/without.md b/docs/reference/array/without.md index 7fb28cc01..51a920624 100644 --- a/docs/reference/array/without.md +++ b/docs/reference/array/without.md @@ -1,30 +1,24 @@ # without -Creates an array excluding all given values using SameValueZero for equality comparisons. +Creates an array that excludes all specified values. -This function takes an input array and returns a new array that excludes all values -specified in the additional arguments. It uses SameValueZero for equality comparisons, -meaning that it considers -0 and +0 as equal but treats NaN as unequal to itself. +It correctly excludes `NaN`, as it compares values using [SameValueZero](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero). ## Signature ```typescript -function without(array: ArrayLike, ...values: T[]): T[]; +function without(array: T[], ...values: T[]): T[]; ``` ### Parameters -- `array` (`ArrayLike`): The array to filter. +- `array` (`T[]`): The array to exclude values. - `values` (`...T[]`): The values to exclude. ### Returns (`T[]`) A new array without the specified values. -### Throws - -Does not throw explicitly but returns an empty array if the input is not a valid array or has invalid array length. - ## Examples ```typescript diff --git a/src/array/without.ts b/src/array/without.ts index dcbb1e4c7..abdf023a8 100644 --- a/src/array/without.ts +++ b/src/array/without.ts @@ -1,12 +1,10 @@ /** - * Creates an array excluding all given values using SameValueZero for equality comparisons. + * Creates an array that excludes all specified values. * - * This function takes an input array and returns a new array that excludes all values - * specified in the second argument. It uses SameValueZero for equality comparisons, - * meaning that it considers -0 and +0 as equal but treats NaN as unequal to itself. + * It correctly excludes `NaN`, as it compares values using [SameValueZero](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero). * * @template T The type of elements in the array. - * @param {ArrayLike} array - The array to filter. + * @param {T[]} array - The array to filter. * @param {...T[]} values - The values to exclude. * @returns {T[]} A new array without the specified values. * @@ -20,10 +18,7 @@ * without(['a', 'b', 'c', 'a'], 'a'); * // Returns: ['b', 'c'] */ -export function without(array: ArrayLike, ...values: T[]): T[] { - if (!array || typeof array.length !== 'number') { - return []; - } +export function without(array: readonly T[], ...values: T[]): T[] { const valuesSet = new Set(values); return Array.prototype.filter.call(array, item => !valuesSet.has(item)); } From 85a0ed6f96cfb1d6c31efe8e4c49ef31ea52d3a7 Mon Sep 17 00:00:00 2001 From: Sojin Park Date: Wed, 3 Jul 2024 09:58:29 +0900 Subject: [PATCH 7/8] Update src/array/without.ts --- src/array/without.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array/without.ts b/src/array/without.ts index abdf023a8..3b39238dc 100644 --- a/src/array/without.ts +++ b/src/array/without.ts @@ -20,5 +20,5 @@ */ export function without(array: readonly T[], ...values: T[]): T[] { const valuesSet = new Set(values); - return Array.prototype.filter.call(array, item => !valuesSet.has(item)); + return array.filter(item => !valuesSet.has(item)); } From 66fd67a5f65d1aeab6667eccf08ac25d23619ae8 Mon Sep 17 00:00:00 2001 From: Sojin Park Date: Wed, 3 Jul 2024 10:01:01 +0900 Subject: [PATCH 8/8] Update src/array/without.spec.ts --- src/array/without.spec.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/array/without.spec.ts b/src/array/without.spec.ts index 78a7d9244..d5da295c4 100644 --- a/src/array/without.spec.ts +++ b/src/array/without.spec.ts @@ -24,12 +24,6 @@ describe('without', () => { expect(without([1, '1', 2, '2'], 1, '2')).toEqual(['1', 2]); }); - it('should return an empty array when input is not a valid array', () => { - expect(without(null as any, 1, 2)).toEqual([]); - expect(without(undefined as any, 1, 2)).toEqual([]); - expect(without({ length: 'invalid' } as any, 1, 2)).toEqual([]); - }); - it('should handle NaN values correctly', () => { expect(without([NaN, 1, 2, NaN, 3], NaN)).toEqual([1, 2, 3]); });