es-toolkit/fp 的 intersectionWith:用自定义比较函数在 pipe 管道中做交集运算

es-toolkit/fp 的 intersectionWith:用自定义比较函数在 pipe 管道中做交集运算 es-toolkit/fp 的 intersectionWith用自定义比较函数在 pipe 管道中做交集运算【免费下载链接】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-toolkites-toolkit 的函数式编程入口es-toolkit/fp提供了一种数据后置data-last的intersectionWith变体先用自定义等值函数配置好比较逻辑得到一个等待数据的函数再放进pipe管道中以自上而下的顺序处理数组。本文以 docs/ja/fp/reference/intersectionWith.md 为骨架结合源码实现与测试用例讲清它的参数语义、惰性求值原理、与普通版intersectionWith的差异以及实际可复制的用法。一、它解决什么问题es-toolkit/array中的普通intersectionWith接受三个参数intersectionWith(firstArr, secondArr, areItemsEqual)。而在函数式编程风格中我们希望把筛选两个数组的交集当作管道中的一步与其他变换map、filter、take等串联起来。于是es-toolkit/fp版的intersectionWith被设计成分两段调用第一段接收secondArray与areItemsEqual配置阶段第二段接收被管道传入的数组数据处理阶段const result pipe(array, intersectionWith(secondArray, areItemsEqual));它返回一个新函数把输入的readonly T[]映射为与secondArray中至少一个值满足areItemsEqual相等判定的元素数组。二、基本用法在pipe中intersectionWith保留那些对secondArray中至少一个值令areItemsEqual返回true的管道数组元素import { intersectionWith, pipe } from es-toolkit/fp; pipe( [{ id: 1 }, { id: 2 }], intersectionWith([{ id: 2 }], (a, b) a.id b.id) ); // [{ id: 2 }]这里areItemsEqual按id属性比较对象因此只有{ id: 2 }保留下来。该示例与 src/fp/array/intersectionWith.spec.ts 中的测试用例完全一致。参数secondArrayreadonly U[]包含比较目标值的数组作为参照集合。areItemsEqual(item: T, other: U) boolean判断两个值是否相等的函数返回true表示相等。返回值(array: readonly T[]) T[]一个把readonly T[]转换为与比较函数匹配的值数组的函数。也就是说intersectionWith(secondArray, areItemsEqual)本身就是一个等待数据的一元函数天然适配pipe。三、源码级解析Eager Lazy 双实现从源码结构看src/fp/array/intersectionWith.ts 同时准备了两套行为并用内部工具组合它们export function intersectionWithT, U( secondArray: readonly U[], areItemsEqual: (item: T, other: U) boolean ): (array: readonly T[]) T[] { function intersectionWithEager(array: readonly T[]): T[] { return intersectionWithToolkit(array, secondArray, areItemsEqual); } const intersectionWithLazy createLazyFunctionT, T((value, _index, emit) { if (secondArray.some(other areItemsEqual(value, other))) { emit(value); } }); return combineEagerAndLazyFunctions(intersectionWithEager, intersectionWithLazy); }Eager 实现直接复用es-toolkit/array的intersectionWith。其核心逻辑用filtersome表达——对firstArr的每个元素检查secondArr中是否存在一个元素令areItemsEqual返回truereturn firstArr.filter(firstItem { return secondArr.some(secondItem { return areItemsEqual(firstItem, secondItem); }); });Lazy 实现用createLazyFunction构造一个逐元素push 式变换。对每个输入值若secondArray中存在某个other令areItemsEqual(value, other)为真就把该值emit给下一级管道。组合combineEagerAndLazyFunctions见 src/fp/_internal/lazy.ts把 eager 函数原样返回并挂上lazy元数据。于是直接调用时行为与普通版完全一致放进pipe时pipe可以识别其惰性变换并与其他惰性函数融合。四、惰性求值为什么它适合放在管道中pipe的融合机制详见 docs/fp/intro.md 与 docs/fp/reference/pipe.md把相邻的惰性函数map、filter、take、intersectionWith等合并为单趟遍历不再每步都产生中间数组而是让每个元素一次性穿过所有阶段当尾部的短路函数如take收集到足够结果时整个遍历立即停止后面的输入不再被访问。intersectionWith的惰性变换在 src/fp/array/intersectionWith.spec.ts 中有明确的测试证据const spy vi.fn((item: { id: number }) item); expect( pipe( [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }], map(spy), intersectionWith([3], (item, id) item.id id), take(1) ) ).toEqual([{ id: 3 }]); expect(spy).toHaveBeenCalledTimes(3);注意spy只被调用了3 次而不是 4 次take(1)收集到第一个结果{ id: 3 }后管道立即短路{ id: 4 }根本不会被map处理。这正是融合 短路带来的收益——数据规模越大、take越早满足节省的遍历就越多。五、实战扩展自定义比较函数的典型场景借助自定义比较函数intersectionWith可以处理普通无法胜任的复杂对象。以下场景来自普通版intersectionWith文档同样适用于fp版只需把调用方式改为管道形式按对象属性比较import { pipe } from es-toolkit/fp; import { intersectionWith } from es-toolkit/fp; const users1 [ { id: 1, name: john }, { id: 2, name: jane }, ]; const users2 [ { id: 2, name: jane }, { id: 3, name: bob }, ]; pipe(users1, intersectionWith(users2, (a, b) a.id b.id)); // [{ id: 2, name: jane }]比较不同类型的值泛型签名areItemsEqual: (item: T, other: U) boolean允许两数组元素类型不同const objects [ { id: 1, name: apple }, { id: 2, name: banana }, ]; const ids [2, 3]; pipe(objects, intersectionWith(ids, (obj, id) obj.id id)); // [{ id: 2, name: banana }]大小写不敏感的字符串比较const words1 [Apple, Banana]; const words2 [apple, cherry]; pipe(words1, intersectionWith(words2, (a, b) a.toLowerCase() b.toLowerCase())); // [Apple]数值容差比较const numbers1 [1.1, 2.3, 3.7]; const numbers2 [1.0, 2.5, 4.0]; pipe(numbers1, intersectionWith(numbers2, (a, b) Math.abs(a - b) 0.5)); // [1.1, 2.3, 3.7]注意返回结果始终来自被管道传入的第一个数组保留其原始元素与顺序secondArray只作为判定依据。六、与普通版如何选择es-toolkit/fp版并不是独立实现的另一套算法而是对es-toolkit/array版的重封装仅改变调用形态。选择建议如下普通代码中直接调用使用原版intersectionWith即intersectionWith(firstArr, secondArr, areItemsEqual)更直观、无额外间接层。需要用pipe串联多个变换时使用本fp版把intersectionWith(secondArray, areItemsEqual)作为管道中的一步享受惰性融合带来的单趟遍历与提前短路收益。迁移 Lodash 调用点可参考es-toolkit/compat入口见 docs/fp/intro.md 的说明。七、相关资源文档docs/ja/fp/reference/intersectionWith.md、英文版 docs/fp/reference/intersectionWith.md、普通版 docs/reference/array/intersectionWith.md管道入口docs/fp/reference/pipe.mdfp 模块总览docs/fp/intro.md源码src/fp/array/intersectionWith.ts、底层普通版 src/array/intersectionWith.ts、惰性求值原语 src/fp/_internal/lazy.ts测试src/fp/array/intersectionWith.spec.ts【免费下载链接】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),仅供参考