From 884773353a2e6fcc277d77e4f0b2246a7360aa3c Mon Sep 17 00:00:00 2001 From: akino <1947055799@qq.com> Date: Mon, 14 Nov 2022 05:50:44 +0000 Subject: [PATCH 1/6] feat(array): add unique muti-type array method. --- src/array.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ src/base.ts | 7 +++++++ 2 files changed, 49 insertions(+) diff --git a/src/array.ts b/src/array.ts index 173bfc8..4184e6f 100644 --- a/src/array.ts +++ b/src/array.ts @@ -1,4 +1,5 @@ import { clamp } from './math' +import { getType } from './base' import type { Arrayable, Nullable } from './types' /** @@ -69,6 +70,47 @@ export function uniq(array: readonly T[]): T[] { return Array.from(new Set(array)) } +/** + * Unique an muti-type Array + * + * @category Array + */ +export function uniqMutiType(array: readonly T[]): T[] { + return array.reduce((acc: Array, cur: any) => { + const isExist = acc.findIndex((item: any) => isEqual(cur, item)); + if (isExist === -1) { + acc.push(cur); + } + return acc; + }, []); + + function isEqual(target1: any, target2: any): boolean { + const t1 = getType(target1); + const t2 = getType(target2); + if (t1 !== t2) { + return false; + } + if (t1 === 'array') { + if (target1.length !== target2.length) { + return false; + } + return target1.every((item: any, i: number) => { + return isEqual(item, target2[i]); + }); + } + if (t1 === 'object') { + const keyArr = Object.keys(target1); + if (keyArr.length !== Object.keys(target2).length) { + return false; + } + return keyArr.every((key: string) => { + return isEqual(target1[key], target2[key]); + }); + } + return target1 === target2; + } +} + /** * Get last item * diff --git a/src/base.ts b/src/base.ts index 04ab0e5..04e3d85 100644 --- a/src/base.ts +++ b/src/base.ts @@ -3,4 +3,11 @@ export const assert = (condition: boolean, message: string): asserts condition = throw new Error(message) } export const toString = (v: any) => Object.prototype.toString.call(v) +export const getType = (v: any) => { + if (v === null) { + return 'null'; + } + const type = toString(v).slice(8, -1).toLowerCase(); + return typeof v === 'object' || typeof v === 'function' ? type : typeof v; +} export const noop = () => {} From b8fb1026aceccb4e4cff199bb8a962430bb73d97 Mon Sep 17 00:00:00 2001 From: akino <1947055799@qq.com> Date: Mon, 14 Nov 2022 05:57:20 +0000 Subject: [PATCH 2/6] perf: remove readonly attr. --- src/array.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array.ts b/src/array.ts index 4184e6f..a100dcc 100644 --- a/src/array.ts +++ b/src/array.ts @@ -75,7 +75,7 @@ export function uniq(array: readonly T[]): T[] { * * @category Array */ -export function uniqMutiType(array: readonly T[]): T[] { +export function uniqMutiType(array: T[]): T[] { return array.reduce((acc: Array, cur: any) => { const isExist = acc.findIndex((item: any) => isEqual(cur, item)); if (isExist === -1) { From 7154cb14dee03b93a823f14b04d928597e608780 Mon Sep 17 00:00:00 2001 From: akino <1947055799@qq.com> Date: Thu, 17 Nov 2022 02:53:03 +0000 Subject: [PATCH 3/6] feat(equal): add equality judgment utility. --- src/equal.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/equal.ts diff --git a/src/equal.ts b/src/equal.ts new file mode 100644 index 0000000..e6fe49a --- /dev/null +++ b/src/equal.ts @@ -0,0 +1,31 @@ +import { getType } from './base' + +export const isTypeEqual = (value1: any, value2: any) => { + return getType(value1) === getType(value2); +} + +export const isDeepEqual = (value1: any, value2: any): boolean => { + const type1 = getType(value1); + const type2 = getType(value2); + if (type1 !== type2) { + return false; + } + if (type1 === 'array') { + if (value1.length !== value2.length) { + return false; + } + return value1.every((item: any, i: number) => { + return isDeepEqual(item, value2[i]); + }); + } + if (type1 === 'object') { + const keyArr = Object.keys(value1); + if (keyArr.length !== Object.keys(value2).length) { + return false; + } + return keyArr.every((key: string) => { + return isDeepEqual(value1[key], value2[key]); + }); + } + return value1 === value2; +} \ No newline at end of file From dcc286f404ec547b93e29e8bac30d03779f9a0d7 Mon Sep 17 00:00:00 2001 From: akino <1947055799@qq.com> Date: Thu, 17 Nov 2022 02:54:46 +0000 Subject: [PATCH 4/6] perf(array): perf the deep unique method. --- src/array.ts | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/src/array.ts b/src/array.ts index a100dcc..ff5f354 100644 --- a/src/array.ts +++ b/src/array.ts @@ -1,5 +1,5 @@ import { clamp } from './math' -import { getType } from './base' +import { isDeepEqual } from './equal' import type { Arrayable, Nullable } from './types' /** @@ -71,44 +71,18 @@ export function uniq(array: readonly T[]): T[] { } /** - * Unique an muti-type Array + * Unique an Array(one type or muti-type) * * @category Array */ -export function uniqMutiType(array: T[]): T[] { - return array.reduce((acc: Array, cur: any) => { - const isExist = acc.findIndex((item: any) => isEqual(cur, item)); - if (isExist === -1) { +export function uniqueBy(array: readonly T[], equalFn = isDeepEqual): T[] { + return array.reduce((acc: T[], cur: any) => { + const index = acc.findIndex((item: any) => equalFn(cur, item)); + if (index === -1) { acc.push(cur); } return acc; }, []); - - function isEqual(target1: any, target2: any): boolean { - const t1 = getType(target1); - const t2 = getType(target2); - if (t1 !== t2) { - return false; - } - if (t1 === 'array') { - if (target1.length !== target2.length) { - return false; - } - return target1.every((item: any, i: number) => { - return isEqual(item, target2[i]); - }); - } - if (t1 === 'object') { - const keyArr = Object.keys(target1); - if (keyArr.length !== Object.keys(target2).length) { - return false; - } - return keyArr.every((key: string) => { - return isEqual(target1[key], target2[key]); - }); - } - return target1 === target2; - } } /** From 1c0398161d213c7c30eb8f9ed39581d5f4d4f814 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 30 Nov 2022 07:58:13 +0800 Subject: [PATCH 5/6] chore: update --- src/array.ts | 16 +++++++--------- src/base.ts | 11 +++++------ src/equal.ts | 54 ++++++++++++++++++++++++---------------------------- 3 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/array.ts b/src/array.ts index ff5f354..644bc97 100644 --- a/src/array.ts +++ b/src/array.ts @@ -1,5 +1,4 @@ import { clamp } from './math' -import { isDeepEqual } from './equal' import type { Arrayable, Nullable } from './types' /** @@ -71,18 +70,17 @@ export function uniq(array: readonly T[]): T[] { } /** - * Unique an Array(one type or muti-type) + * Unique an Array by a custom equality function * * @category Array */ -export function uniqueBy(array: readonly T[], equalFn = isDeepEqual): T[] { +export function uniqueBy(array: readonly T[], equalFn: (a: any, b: any) => boolean): T[] { return array.reduce((acc: T[], cur: any) => { - const index = acc.findIndex((item: any) => equalFn(cur, item)); - if (index === -1) { - acc.push(cur); - } - return acc; - }, []); + const index = acc.findIndex((item: any) => equalFn(cur, item)) + if (index === -1) + acc.push(cur) + return acc + }, []) } /** diff --git a/src/base.ts b/src/base.ts index 04e3d85..03e5656 100644 --- a/src/base.ts +++ b/src/base.ts @@ -3,11 +3,10 @@ export const assert = (condition: boolean, message: string): asserts condition = throw new Error(message) } export const toString = (v: any) => Object.prototype.toString.call(v) -export const getType = (v: any) => { - if (v === null) { - return 'null'; - } - const type = toString(v).slice(8, -1).toLowerCase(); - return typeof v === 'object' || typeof v === 'function' ? type : typeof v; +export const getTypeName = (v: any) => { + if (v === null) + return 'null' + const type = toString(v).slice(8, -1).toLowerCase() + return typeof v === 'object' || typeof v === 'function' ? type : typeof v } export const noop = () => {} diff --git a/src/equal.ts b/src/equal.ts index e6fe49a..a01129d 100644 --- a/src/equal.ts +++ b/src/equal.ts @@ -1,31 +1,27 @@ -import { getType } from './base' - -export const isTypeEqual = (value1: any, value2: any) => { - return getType(value1) === getType(value2); -} +import { getTypeName } from './base' export const isDeepEqual = (value1: any, value2: any): boolean => { - const type1 = getType(value1); - const type2 = getType(value2); - if (type1 !== type2) { - return false; - } - if (type1 === 'array') { - if (value1.length !== value2.length) { - return false; - } - return value1.every((item: any, i: number) => { - return isDeepEqual(item, value2[i]); - }); - } - if (type1 === 'object') { - const keyArr = Object.keys(value1); - if (keyArr.length !== Object.keys(value2).length) { - return false; - } - return keyArr.every((key: string) => { - return isDeepEqual(value1[key], value2[key]); - }); - } - return value1 === value2; -} \ No newline at end of file + const type1 = getTypeName(value1) + const type2 = getTypeName(value2) + if (type1 !== type2) + return false + + if (type1 === 'array') { + if (value1.length !== value2.length) + return false + + return value1.every((item: any, i: number) => { + return isDeepEqual(item, value2[i]) + }) + } + if (type1 === 'object') { + const keyArr = Object.keys(value1) + if (keyArr.length !== Object.keys(value2).length) + return false + + return keyArr.every((key: string) => { + return isDeepEqual(value1[key], value2[key]) + }) + } + return value1 === value2 +} From 89a3dc7e5b2308157359c813cc69c0660513ec70 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 30 Nov 2022 07:59:02 +0800 Subject: [PATCH 6/6] chore: type --- src/equal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/equal.ts b/src/equal.ts index a01129d..93a4cbc 100644 --- a/src/equal.ts +++ b/src/equal.ts @@ -1,6 +1,6 @@ import { getTypeName } from './base' -export const isDeepEqual = (value1: any, value2: any): boolean => { +export function isDeepEqual(value1: any, value2: any): boolean { const type1 = getTypeName(value1) const type2 = getTypeName(value2) if (type1 !== type2)