計(jì)算數(shù)組差集(Lodash 兼容版與高性能版對(duì)比))
es-toolkit 的 differenceWith 詳解用自定義比較函數(shù)計(jì)算數(shù)組差集Lodash 兼容版與高性能版對(duì)比【免費(fèi)下載鏈接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/es/es-toolkitdifferenceWith是 es-toolkit 中用于「按自定義比較邏輯求數(shù)組差集」的工具函數(shù)它在es-toolkit/compat兼容入口中完整復(fù)刻了 Lodash 的行為不僅支持多個(gè)排除數(shù)組、ArrayLike與null/undefined容錯(cuò)還能在省略比較函數(shù)時(shí)自動(dòng)退化為普通difference語(yǔ)義。讀完本文你將掌握differenceWith的完整用法、參數(shù)約定、與 Lodash 的兼容細(xì)節(jié)如-0/NaN處理并能通過(guò)源碼與測(cè)試用例理解 compat 版為何比現(xiàn)代版更重、以及在什么場(chǎng)景下應(yīng)該改用 es-toolkit 原生版。一、函數(shù)簽名與核心語(yǔ)義differenceWith的作用是使用一個(gè)自定義比較函數(shù)comparator來(lái)判斷兩個(gè)元素是否相等然后從第一個(gè)數(shù)組中剔除所有在其余數(shù)組中出現(xiàn)過(guò)的元素返回一個(gè)新的數(shù)組。其 TypeScript 簽名compat 版如下differenceWith(array, ...values, comparator);arrayArrayLikeT | null | undefined求差集的基準(zhǔn)數(shù)組。...valuesArrayArrayLikeT(a: T, b: T) boolean一個(gè)或多個(gè)需要排除的數(shù)組其中最后一個(gè)參數(shù)是比較函數(shù)。返回值T[]按比較函數(shù)剔除后的新數(shù)組原數(shù)組不會(huì)被修改。與 Lodash 一致比較函數(shù)必須放在最后一個(gè)參數(shù)位置如果省略比較函數(shù)函數(shù)行為與普通difference完全相同。二、基礎(chǔ)用法按對(duì)象字段求差集最常見(jiàn)的場(chǎng)景是對(duì)象數(shù)組之間按某個(gè)字段如id比較import { differenceWith } from es-toolkit/compat; // 按 id 比較對(duì)象 const objects [{ id: 1 }, { id: 2 }, { id: 3 }]; const others [{ id: 2 }]; const comparator (a, b) a.id b.id; differenceWith(objects, others, comparator); // Returns: [{ id: 1 }, { id: 3 }]這里{ id: 2 }與排除數(shù)組中的{ id: 2 }經(jīng)比較函數(shù)判定相等因此被剔除其余元素保留。由于比較邏輯完全由你控制它也能比較不同類型的數(shù)組例如對(duì)象與數(shù)字// 對(duì)象 id 與數(shù)字直接比較對(duì)應(yīng)現(xiàn)代版 es-toolkit 的用法 import { differenceWith } from es-toolkit/array; const objects [{ id: 1 }, { id: 2 }, { id: 3 }]; const numbers [2, 4]; const areItemsEqual (a, b) a.id b; differenceWith(objects, numbers, areItemsEqual); // Returns: [{ id: 1 }, { id: 3 }]三、多數(shù)組一次排除differenceWith支持同時(shí)傳入多個(gè)排除數(shù)組元素只要與其中任意一個(gè)數(shù)組中的元素匹配即被剔除import { differenceWith } from es-toolkit/compat; const array [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]; const values1 [{ id: 2 }]; const values2 [{ id: 3 }]; differenceWith(array, values1, values2, comparator); // Returns: [{ id: 1 }, { id: 4 }]從源碼看compat 實(shí)現(xiàn)會(huì)對(duì)...values做一次扁平化合并再統(tǒng)一與基準(zhǔn)數(shù)組比較見(jiàn) flattenArrayLike// src/compat/array/differenceWith.ts核心邏輯節(jié)選 const comparator last(values); const flattenedValues flattenArrayLike(values as ArrayArrayLikeT); if (typeof comparator function) { return differenceWithToolkit(Array.from(array), flattenedValues, comparator); } return differenceToolkit(Array.from(array), flattenedValues).map(normalizeZero);也就是說(shuō)先取出最后一個(gè)參數(shù)判斷是否為函數(shù)若為函數(shù)則作為比較器否則整批參數(shù)都按數(shù)組處理。flattenArrayLike會(huì)跳過(guò)其中不是ArrayLike的值isArrayLikeObject判斷這也是 compat 版比原生版多出的容錯(cuò)成本之一。四、省略比較函數(shù)退化為普通 difference當(dāng)最后一個(gè)參數(shù)不是函數(shù)例如全是數(shù)組時(shí)differenceWith會(huì)回退到基于SameValueZero算法的普通差集計(jì)算效果等同于differenceimport { differenceWith } from es-toolkit/compat; // 不使用比較函數(shù)時(shí)執(zhí)行普通比較 differenceWith([1, 2, 3], [2], [3]); // Returns: [1]這條回退路徑在源碼中對(duì)應(yīng)return differenceToolkit(Array.from(array), flattenedValues).map(normalizeZero);其中differenceToolkit是 src/array/difference.ts 中的現(xiàn)代實(shí)現(xiàn)內(nèi)部借助Set完成 O(n) 級(jí)別的去重判斷。注意末尾的.map(normalizeZero)這是為了對(duì)齊 Lodash 行為把結(jié)果中的-0規(guī)范化為0見(jiàn) normalizeZero。五、復(fù)雜比較邏輯自定義相等規(guī)則比較函數(shù)完全由你定義因此可以實(shí)現(xiàn)「只看部分字段」這類復(fù)雜規(guī)則。例如只按name判斷用戶是否相同即使年齡不同也會(huì)被排除import { differenceWith } from es-toolkit/compat; const users [ { name: alice, age: 25 }, { name: bob, age: 30 }, { name: charlie, age: 35 }, ]; const excludeUsers [{ name: bob, age: 25 }]; // 年齡不同 // 只按名字比較 const compareByName (a, b) a.name b.name; differenceWith(users, excludeUsers, compareByName); // Returns: [{ name: alice, age: 25 }, { name: charlie, age: 35 }] // bob 被排除年齡不同但名字相同現(xiàn)代版 docs/reference/array/differenceWith.md 也演示了同樣的能力兩個(gè)對(duì)象數(shù)組即使age不同只要name相同即視為同一用戶。比較函數(shù)同樣支持直接引入isEqual做深比較import { differenceWith } from es-toolkit/compat; import { isEqual } from es-toolkit; const objects [ { x: 1, y: 2 }, { x: 2, y: 1 }, ]; differenceWith(objects, [{ x: 1, y: 2 }], isEqual); // Returns: [{ x: 2, y: 1 }]六、邊界行為與測(cè)試驗(yàn)證compat 版的細(xì)節(jié)行為均有對(duì)應(yīng)的測(cè)試用例保障見(jiàn) src/compat/array/differenceWith.spec.ts測(cè)試覆蓋了 Lodash 官方用例并補(bǔ)充了更多邊界-0與0互相匹配結(jié)果歸一化為0differenceWith([-0, 1], [1])返回[0][-0, 0]與[0]求差集得到[]。NaN匹配differenceWith([1, NaN, 3], [NaN, 5, NaN])返回[1, 3]說(shuō)明走SameValueZero語(yǔ)義時(shí)NaN等于自身。大數(shù)組測(cè)試使用LARGE_ARRAY_SIZE構(gòu)造大規(guī)模輸入驗(yàn)證-0、NaN、對(duì)象引用在大量數(shù)據(jù)下行為一致differenceWith([-0, 1], largeArray)仍返回[0]。忽略非 ArrayLike 參數(shù)differenceWith(null, array, 1)返回[]differenceWith(array, args, null)跳過(guò)非法參數(shù)基準(zhǔn)數(shù)組不是ArrayLike時(shí)直接返回空數(shù)組對(duì)應(yīng)源碼開(kāi)頭的if (!isArrayLikeObject(array)) return [];。顯式 comparator 時(shí)保留0的符號(hào)使用eq作為比較函數(shù)時(shí)-0會(huì)按原樣保留[-0]因?yàn)閚ormalizeZero只作用于無(wú)比較函數(shù)的回退路徑。七、compat 版與原生版如何選擇官方文檔在 compat 參考頁(yè)頂部給出了明確建議見(jiàn) docs/compat/reference/array/differenceWith.md 及日文版 docs/ja/compat/reference/array/differenceWith.md 的警告框這個(gè)differenceWith函數(shù)因?yàn)橐幚韓ull/undefined、多數(shù)組處理以及ArrayLike類型處理運(yùn)行會(huì)變慢。建議改用更快、更現(xiàn)代的 es-toolkit 原生differenceWith。兩者差異一覽對(duì)比維度es-toolkit/compat版es-toolkit/array原生版入口import { differenceWith } from es-toolkit/compatimport { differenceWith } from es-toolkit/array簽名differenceWith(array, ...values, comparator)differenceWith(firstArr, secondArr, areItemsEqual)多數(shù)組支持內(nèi)部先f(wàn)lattenArrayLike合并僅兩個(gè)數(shù)組空值容錯(cuò)null/undefined/非ArrayLike自動(dòng)處理要求真實(shí)數(shù)組默認(rèn)比較SameValueZero-0歸一化normalizeZero基于Set的嚴(yán)格相等實(shí)現(xiàn)src/compat/array/differenceWith.tssrc/array/differenceWith.ts原生版的核心實(shí)現(xiàn)非常精簡(jiǎn)直接對(duì)兩個(gè)數(shù)組做過(guò)濾// src/array/differenceWith.ts return firstArr.filter(firstItem { return secondArr.every(secondItem { return !areItemsEqual(firstItem, secondItem); }); });因此如果是新項(xiàng)目且只需在兩個(gè)數(shù)組間做自定義比較應(yīng)優(yōu)先使用es-toolkit/array的原生differenceWith只有當(dāng)需要從 Lodash 遷移、依賴多數(shù)組與寬松參數(shù)容錯(cuò)時(shí)才使用es-toolkit/compat入口該入口在 src/compat/compat.ts 中統(tǒng)一導(dǎo)出。八、小結(jié)differenceWith是處理「非嚴(yán)格相等」差集需求的利器通過(guò)一個(gè)比較函數(shù)就能按對(duì)象字段、部分屬性乃至任意自定義規(guī)則求差集。compat 版在保留 Lodash 全部兼容行為多數(shù)組、空值容錯(cuò)、-0/NaN語(yǔ)義的同時(shí)與現(xiàn)代版共享同一套核心算法src/array/differenceWith.ts并借助Set實(shí)現(xiàn)的高效difference與normalizeZero保證結(jié)果與 Lodash 一致。結(jié)合 測(cè)試用例 中覆蓋的邊界場(chǎng)景你可以放心地在遷移 Lodash 代碼或處理復(fù)雜對(duì)象比較時(shí)使用它?!久赓M(fèi)下載鏈接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考