diff --git a/docs/.vitepress/items/array.ts b/docs/.vitepress/items/array.ts index 205b5f7..36d7a53 100644 --- a/docs/.vitepress/items/array.ts +++ b/docs/.vitepress/items/array.ts @@ -5,6 +5,8 @@ export const arrayItems = [ { text: 'uniqBy', link: '/array/uniq-by' }, { text: 'difference', link: '/array/difference' }, { text: 'differenceWith', link: '/array/difference-with' }, + { text: 'intersection', link: '/array/intersection' }, + { text: 'intersectionWith', link: '/array/intersection-with' }, { text: 'find', link: '/array/find' }, { text: 'shuffle', link: '/array/shuffle' }, { text: 'removeItem', link: '/array/remove-item' }, diff --git a/docs/array/intersection-with.md b/docs/array/intersection-with.md new file mode 100644 index 0000000..12f6e6f --- /dev/null +++ b/docs/array/intersection-with.md @@ -0,0 +1,36 @@ +# intersectionWith + +Creates an `array` of unique values ​​contained in all given arrays, and supports custom comparison functions. + +### Usage + +```ts +import { intersectionWith } from 'rattail' + +intersectionWith( + [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 3 }], + [{ num: 2 }, { num: 3 }, { num: 4 }], + (a, b) => a.num === b.num, +) +// return [{ num: 2 }, { num: 3 }] +intersectionWith( + [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 3 }], + [{ num: 2 }, { num: 3 }, { num: 4 }], + [{ num: 3 }, { num: 4 }, { num: 5 }], + (a, b) => a.num === b.num, +) +// return [{ num: 3 }] +``` + +### Arguments + +| Arg | Type | Defaults | +| ----------- | ------------------------- | -------- | +| `...values` | `Array` | | +| `fn` | `(a: any, b: any) => any` | | + +### Return + +| Type | +| ------- | +| `Array` | diff --git a/docs/array/intersection.md b/docs/array/intersection.md new file mode 100644 index 0000000..3a530e4 --- /dev/null +++ b/docs/array/intersection.md @@ -0,0 +1,26 @@ +# intersection + +Creates an `array` of unique values ​​contained in all given arrays. + +### Usage + +```ts +import { intersection } from 'rattail' + +intersection([1, 2, 3, 3], [2, 3, 4]) +// return [2, 3] +intersection([1, 2, 3, 3], [2, 3, 4], [3, 4, 5]) +// return [3] +``` + +### Arguments + +| Arg | Type | Defaults | +| ----------- | -------------- | -------- | +| `...values` | `Array` | | + +### Return + +| Type | +| ------- | +| `Array` | diff --git a/docs/zh/array/intersection-with.md b/docs/zh/array/intersection-with.md new file mode 100644 index 0000000..7edfd58 --- /dev/null +++ b/docs/zh/array/intersection-with.md @@ -0,0 +1,36 @@ +# intersectionWith + +创建一个去重数组,数组中的每个值都被包含在所有的给定数组中(数组取交集),支持传入比较函数。 + +### 使用 + +```ts +import { intersectionWith } from 'rattail' + +intersectionWith( + [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 3 }], + [{ num: 2 }, { num: 3 }, { num: 4 }], + (a, b) => a.num === b.num, +) +// return [{ num: 2 }, { num: 3 }] +intersectionWith( + [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 3 }], + [{ num: 2 }, { num: 3 }, { num: 4 }], + [{ num: 3 }, { num: 4 }, { num: 5 }], + (a, b) => a.num === b.num, +) +// return [{ num: 3 }] +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| ----------- | ------------------------- | ------ | +| `...values` | `Array` | | +| `fn` | `(a: any, b: any) => any` | | + +### 返回值 + +| 类型 | +| ------- | +| `Array` | diff --git a/docs/zh/array/intersection.md b/docs/zh/array/intersection.md new file mode 100644 index 0000000..9fe8a8e --- /dev/null +++ b/docs/zh/array/intersection.md @@ -0,0 +1,26 @@ +# intersection + +创建一个去重数组,数组中的每个值都被包含在所有的给定数组中(数组取交集)。 + +### 使用 + +```ts +import { intersection } from 'rattail' + +intersection([1, 2, 3, 3], [2, 3, 4]) +// return [2, 3] +intersection([1, 2, 3, 3], [2, 3, 4], [3, 4, 5]) +// return [3] +``` + +### 参数 + +| 参数 | 类型 | 默认值 | +| ----------- | -------------- | ------ | +| `...values` | `Array` | | + +### 返回值 + +| 类型 | +| ------- | +| `Array` | diff --git a/src/array/index.ts b/src/array/index.ts index c8f74b3..af3175c 100644 --- a/src/array/index.ts +++ b/src/array/index.ts @@ -11,3 +11,5 @@ export * from './removeArrayEmpty' export * from './normalizeToArray' export * from './difference' export * from './differenceWith' +export * from './intersection' +export * from './intersectionWith' diff --git a/src/array/intersection.ts b/src/array/intersection.ts new file mode 100644 index 0000000..9191e84 --- /dev/null +++ b/src/array/intersection.ts @@ -0,0 +1,5 @@ +import { intersectionWith } from './intersectionWith' + +export function intersection(...values: T[][]): T[] { + return intersectionWith(...values, (a, b) => a === b) +} diff --git a/src/array/intersectionWith.ts b/src/array/intersectionWith.ts new file mode 100644 index 0000000..cb19331 --- /dev/null +++ b/src/array/intersectionWith.ts @@ -0,0 +1,26 @@ +import { at } from './at' +import { uniqBy } from './uniqBy' + +type Fn = (a: T, b: T) => any + +export function intersectionWith(...values: [...T[][], fn: Fn]): T[] { + const fn = at(values, -1) as Fn + const targets = values.slice(0, -1) as T[][] + + if (targets.length === 0) { + return [] + } + + if (targets.length === 1) { + return uniqBy(targets[0], fn) + } + + function baseIntersectionWith(arr1: T[], arr2: T[]): T[] { + return arr1.filter((item) => arr2.some((value) => fn(item, value))) + } + + return uniqBy( + targets.reduce((result, target) => baseIntersectionWith(result, target)), + fn, + ) +} diff --git a/tests/array.spec.ts b/tests/array.spec.ts index 920c561..4f4001b 100644 --- a/tests/array.spec.ts +++ b/tests/array.spec.ts @@ -13,6 +13,8 @@ import { chunk, difference, differenceWith, + intersection, + intersectionWith, } from '../src' it('uniq', () => { @@ -98,22 +100,61 @@ it('chunk', () => { }) it('difference', () => { - expect(difference([1, 2, 3, 4])).toEqual([1, 2, 3, 4]) - expect(difference([1, 2, 3, 4], [2, 3])).toEqual([1, 4]) - expect(difference([1, 2, 3, 4], [2, 3], [3, 4])).toEqual([1]) + const a = [1, 2, 3, 4] + expect(difference(a)).toEqual([1, 2, 3, 4]) + expect(difference(a)).not.toBe(a) + + const b = [1, 2, 3, 4] + expect(difference(b, [2, 3])).toEqual([1, 4]) + expect(difference(b, [2, 3])).not.toBe(b) + + const c = [1, 2, 3, 4] + expect(difference(c, [2, 3], [3, 4])).toEqual([1]) + expect(difference(c, [2, 3], [3, 4])).not.toBe(c) }) it('differenceWith', () => { - expect(differenceWith([{ num: 1 }, { num: 2 }, { num: 3 }], (a, b) => a.num === b.num)).toEqual([ - { num: 1 }, - { num: 2 }, - { num: 3 }, - ]) - expect(differenceWith([{ num: 1 }, { num: 2 }, { num: 3 }], [{ num: 2 }], (a, b) => a.num === b.num)).toEqual([ - { num: 1 }, - { num: 3 }, - ]) - expect( - differenceWith([{ num: 1 }, { num: 2 }, { num: 3 }], [{ num: 2 }], [{ num: 3 }], (a, b) => a.num === b.num), - ).toEqual([{ num: 1 }]) + const a = [{ num: 1 }, { num: 2 }, { num: 3 }] + expect(differenceWith(a, (a, b) => a.num === b.num)).toEqual([{ num: 1 }, { num: 2 }, { num: 3 }]) + expect(differenceWith(a, (a, b) => a.num === b.num)).not.toBe(a) + + const b = [{ num: 1 }, { num: 2 }, { num: 3 }] + expect(differenceWith(b, [{ num: 2 }], (a, b) => a.num === b.num)).toEqual([{ num: 1 }, { num: 3 }]) + expect(differenceWith(b, [{ num: 2 }], (a, b) => a.num === b.num)).not.toBe(b) + + const c = [{ num: 1 }, { num: 2 }, { num: 3 }] + expect(differenceWith(c, [{ num: 2 }], [{ num: 3 }], (a, b) => a.num === b.num)).toEqual([{ num: 1 }]) + expect(differenceWith(c, [{ num: 2 }], [{ num: 3 }], (a, b) => a.num === b.num)).not.toBe(c) +}) + +it('intersection', () => { + expect(intersection()).toEqual([]) + + const a = [1, 2, 3, 3] + expect(intersection(a)).toEqual([1, 2, 3]) + expect(intersection(a)).not.toBe(a) + + const b = [1, 2, 3, 3] + expect(intersection(b, [2, 3, 4])).toEqual([2, 3]) + expect(intersection(b, [2, 3, 4])).not.toBe(b) + + const c = [1, 2, 3, 3] + expect(intersection(c, [2, 3, 4], [3, 4, 5])).toEqual([3]) + expect(intersection(c, [2, 3, 4], [3, 4, 5])).not.toBe(c) +}) + +it('intersectionWith', () => { + expect(intersectionWith((a, b) => a === b)).toEqual([]) + + const a = [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 3 }] + expect(intersectionWith(a, (a, b) => a.num === b.num)).toEqual([{ num: 1 }, { num: 2 }, { num: 3 }]) + expect(intersectionWith(a, (a, b) => a.num === b.num)).not.toBe(a) + + const b = [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 3 }] + expect(intersectionWith(b, [{ num: 2 }], (a, b) => a.num === b.num)).toEqual([{ num: 2 }]) + expect(intersectionWith(b, [{ num: 2 }], (a, b) => a.num === b.num)).not.toBe(b) + + const c = [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 3 }] + expect(intersectionWith(c, [{ num: 2 }], [{ num: 3 }], (a, b) => a.num === b.num)).toEqual([]) + expect(intersectionWith(c, [{ num: 2 }], [{ num: 3 }], (a, b) => a.num === b.num)).not.toBe(c) })