es-toolkit 的 xorBy:基于映射函数的两数组对称差集详解

发布时间:2026/9/17 9:18:23
es-toolkit 的 xorBy:基于映射函数的两数组对称差集详解 es-toolkit 的 xorBy基于映射函数的两数组对称差集详解【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit本指南围绕 es-toolkit 数组工具库中的xorBy函数展开讲解它如何在先通过映射函数变换、再比较的语义下计算两个数组的对称差集symmetric difference并结合 src/array/xorBy.ts 的源码实现与 src/array/xorBy.spec.ts 的测试用例说明其使用场景、参数约束、边界行为与底层原理。读完本文你将能够熟练使用xorBy处理对象数组、按任意维度去重比较并理解它与xor、unionBy、intersectionBy、differenceBy等函数的组合关系。xorBy 是什么带映射基准的对称差集在集合论中两个集合的对称差集是指仅属于其中一个集合、但不同时属于两个集合的元素集合。es-toolkit 的xorBy就是这一概念的数组实现特殊之处在于它不直接比较元素本身而是先通过用户提供的mapper函数把每个元素变换成比较基准值再基于这些基准值计算对称差集。const result xorBy(arr1, arr2, mapper);这在处理对象数组时尤为实用——两个数组中的对象引用各不相同直接比较毫无意义但提取出id、length等字段后即可准确判断哪些记录只存在于一边。基本用法import { xorBy } from es-toolkit/array; // 按对象的 id 求对称差集 xorBy([{ id: 1 }, { id: 2 }], [{ id: 2 }, { id: 3 }], obj obj.id); // Returns: [{ id: 1 }, { id: 3 }] // 按字符串长度求对称差集 xorBy([apple, banana], [grape, cherry, apple], str str.length); // Returns: [] (所有长度都出现重复)第一个例子中id为 2 的对象在两个数组中同时出现属于交集被剔除id为 1、3 的对象各只出现在一个数组中被保留。第二个例子中四个字符串的长度分别为 5、6、5、6全部在两侧重复因此对称差集为空。映射结果相同的元素被视作同一个xorBy的一个关键语义是凡是映射函数输出相同值的元素在比较时都视作同一个元素因此无需关心元素原始值是否相等。import { xorBy } from es-toolkit/array; xorBy([1, 2, 3, 4], [3, 4, 5, 6], n n % 3); // Returns: [] (所有余数均出现重复)这里映射结果为n % 3第一个数组的余数为 1、2、0、1第二个数组的余数为 0、1、2、0集合 {0, 1, 2} 在两数组中完全重合故结果为空数组。可见xorBy关注的是映射后的取值域是否重合而非元素本身。参数与返回值xorBy的完整签名见 src/array/xorBy.tsexport function xorByT, U(arr1: readonly T[], arr2: readonly T[], mapper: (item: T) U): T[]arr1readonly T[]参与比较的第一个数组只读函数不会修改它。arr2readonly T[]参与比较的第二个数组同样只读。mapper(item: T) U把每个元素转换为比较基准值的函数其返回类型U即比较键的类型。返回值T[]一个新数组包含基于映射结果计算出的对称差集元素原数组不被改动。由于泛型T、U的存在mapper可以返回任意可比较类型——数字、字符串、布尔值均可Set/Map结构对它们使用 SameValueZero 语义判等。源码原理union、intersection、difference 的三段式组合xorBy的实现极为精简其核心思想可以概括为一条公式对称差集 并集 − 交集// 源码src/array/xorBy.ts export function xorByT, U(arr1: readonly T[], arr2: readonly T[], mapper: (item: T) U): T[] { const union unionBy(arr1, arr2, mapper); const intersection intersectionBy(arr1, arr2, mapper); return differenceBy(union, intersection, mapper); }三个步骤分别委托给三个同族函数unionBy(arr1, arr2, mapper)先合并两个数组再按映射值去重得到映射基准下的并集。src/array/unionBy.ts 的实现是uniqBy(arr1.concat(arr2), mapper)而uniqBy见 src/array/uniqBy.ts使用Map记录映射值并保留首次出现的元素保证去重后仍按原顺序排列。intersectionBy(arr1, arr2, mapper)找出映射基准下同时存在于两个数组的元素。src/array/intersectionBy.ts 先把第二个数组整体映射后放入Set再遍历第一个数组命中即保留并从 Set 中删除该键因此重复元素只计一次。differenceBy(union, intersection, mapper)从并集中剔除交集src/array/differenceBy.ts 同样是先映射成 Set、再过滤的写法最终留下的就是只属于某一侧的对称差集元素。这一三段式设计与无映射版本xor完全同构——src/array/xor.ts 的实现是difference(union(arr1, arr2), intersection(arr1, arr2))。可以推断xorBy就是把xor的union/intersection/difference全部替换为带mapper的*By变体从而把按值比较升级为按映射基准比较。边界行为与测试佐证src/array/xorBy.spec.ts 使用 Vitest 覆盖了多种边界场景可作为理解函数行为的权威参考输入mapper期望输出说明[1,2,3,4]/[3,4,5,6]恒等函数[1,2,5,6]常规对称差集[{id:1},{id:2}]/[{id:2},{id:3}]obj obj.id[{id:1},{id:3}]对象按 id 比较[1,2,3]/[4,5,6]恒等函数[1,2,3,4,5,6]无交集时退化为并集[1,2,3]/[1,2,3]恒等函数[]完全重合时为空集[]/[1,2,3]恒等函数[1,2,3]空数组与任意数组的对称差集即对方[1,2,3]/[]恒等函数[1,2,3]同上方向无关这些用例同时验证了对称差集的交换律xorBy(a, b)与xorBy(b, a)结果一致以及空数组参与时返回另一数组内容的退化行为。其中对象按id去重的用例直接对应文档示例恒等映射用例则说明xorBy(arr1, arr2, x x)与xor(arr1, arr2)在数值数组上等价。与同族函数的对比与选型xorBy位于 es-toolkit 数组工具家族的集合运算梯队中与其关系最密切的是xor无映射版本直接比较元素值适合原始类型数组unionBy/intersectionBy/differenceBy分别计算并集、交集、差集均为非对称xorBy恰是它们的组合xorWith另一变体支持自定义比较器而非映射函数适合需要两两比较的复杂场景。选型建议当比较基准是由元素派生的某个键如对象属性、取模结果、字符串长度时选xorBy当只需按元素本身判等时选xor即可获得更少的一次映射开销。使用注意事项映射函数应保持纯函数性mapper会在unionBy、intersectionBy、differenceBy三个阶段被多次调用若依赖外部可变状态或产生副作用可能得到不一致结果。比较基于映射值而非原值两个原始值不同、但映射结果相同的元素会被当作重复项处理这与文档映射函数结果相同的元素视为一个的语义一致。不会修改原数组所有中间结果均为新数组arr1、arr2始终保持只读可放心用于函数式编程流水线。小结xorBy用最简洁的三行组合实现了基于映射基准的对称差集其unionBy − intersectionBy的架构既保证了与无映射版本xor语义的一致性又通过Map/Set保持了 O(n) 级别的查找效率。无论是按对象id同步数据、按字符串长度归类去重还是按任意维度求只属于一边的元素它都是 es-toolkit 中开箱即用的标准答案。【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考