尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

es-toolkit/fp 函数式编程指南:unzipWith 实现分组数组的按位重组与聚合

发布时间:2026/9/16 15:20:16

资讯中心
01
ARTICLE

es-toolkit/fp 函数式编程指南:unzipWith 实现分组数组的按位重组与聚合

es-toolkit/fp 函数式编程指南:unzipWith 实现分组数组的按位重组与聚合
es-toolkit/fp 函数式编程指南unzipWith 实现分组数组的按位重组与聚合【免费下载链接】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 函数式编程入口es-toolkit/fp中的数组工具unzipWith讲解如何在pipe数据流水线中将按位置分组的二维数组重新拆组并用自定义iteratee聚合同一位置的元素。读完本文你将掌握unzipWith(iteratee)的签名、参数与返回值约定、在pipe中的组合方式以及它底层如何复用主库实现完成按列聚合的完整原理。一、unzipWith 是什么在es-toolkit/fp中unzipWith用于重新分组已压缩zipped的数组并对每个位置上的元素做组合。它是unzip的增强版unzip只负责把分组数组按位置拆开而unzipWith在拆开的同时把同一位置的元素交给iteratee合并成一个新值。它最典型的用法是配合pipe使用作为数据流水线中的一个操作符const result pipe(array, unzipWith(iteratee));从源码结构看es-toolkit/fp中所有数组函数都遵循统一的data-last调用约定先传入配置参数这里是iteratee返回一个等待数据到达的函数再由pipe把数据喂进去。这一点在 docs/fp/intro.md 中有明确说明。::: info在普通代码中优先使用 es-toolkit 主库的unzipWith只有在使用pipe组合变换时才使用es-toolkit/fp的这个函数式变体。:::二、基础用法在 pipe 中按位聚合unzipWith会从分组的行中收集同一位置的数值将这些值作为参数调用iteratee并把每次调用的返回值按顺序组成结果数组返回。import { pipe, unzipWith } from es-toolkit/fp; pipe( [ [1, 10], [2, 20], ], unzipWith((a, b) a b) ); // [3, 30]这个例子的执行过程可以拆解为输入是一个包含两行的二维数组[[1, 10], [2, 20]]unzipWith按列取值第 0 列取到1和2第 1 列取到10和20iteratee依次执行1 2 3与10 20 30结果数组为[3, 30]。该行为由 src/fp/array/unzipWith.spec.ts 中的测试用例直接验证import { describe, expect, it } from vitest; import { unzipWith } from ./unzipWith.ts; import { pipe } from ../pipe.ts; describe(unzipWith, () { it(works in a pipe, () { expect( pipe( [ [1, 10], [2, 20], ], unzipWith((a, b) a b) ) ).toEqual([3, 30]); }); });三、参数与返回值参数iteratee(...args: T[]) R用于组合同一位置元素的函数。它接收从每行同一位置收集到的值作为参数返回一个合并后的新值。返回值(target: readonly T[][]) R[]一个函数接收按位置分组的二维数组作为输入返回按位置组合后的结果数组。这里值得注意类型设计iteratee是可变参数variadic类型为(...args: T[]) R意味着同一位置的元素个数不固定取决于输入二维数组的行数。返回的函数输入类型为readonly T[][]只读修饰保证了该操作符不会修改原始数据。四、底层实现从 fp 变体到主库核心es-toolkit/fp的unzipWith本身是一个薄封装层。查看 src/fp/array/unzipWith.ts 可以看到它把传入的iteratee捕获进闭包返回一个等待数据的函数并在数据到达时直接委托给主库实现import { unzipWith as unzipWithToolkit } from ../../array/unzipWith.ts; export function unzipWithT, R(iteratee: (...args: T[]) R): (target: readonly T[][]) R[] { return function (target: readonly T[][]): R[] { return unzipWithToolkit(target, iteratee); }; }真正的按位聚合逻辑在主库 src/array/unzipWith.ts 中完成export function unzipWithT, R(target: readonly T[][], iteratee: (...args: T[]) R): R[] { const maxLength Math.max(0, ...target.map(innerArray innerArray.length)); const result: R[] new Array(maxLength); for (let i 0; i maxLength; i) { const group new Array(target.length); for (let j 0; j target.length; j) { group[j] target[j][i]; } result[i] iteratee(...group); } return result; }算法核心可以归纳为三步确定结果长度用Math.max(0, ...target.map(inner inner.length))求出所有行中最长的长度作为结果数组的长度。Math.max(0, ...)的写法还保证了空数组输入时长度为 0不会出现Math.max()返回-Infinity的边界问题按列收集外层循环i遍历列下标内层循环j遍历行下标把target[j][i]第j行第i列收集进group即同一位置的值应用 iterateeresult[i] iteratee(...group)把整组值展开作为参数传给iteratee结果存入结果数组对应位置。这段实现的时间复杂度为 O(行数 × 列数)即与二维数组元素总数成正比且不产生中间数组group仅是一个行数的临时小数组保持了 es-toolkit 一贯的轻量风格。五、行为细节与边界情况1. 行长度不一致时缺失位置传入 undefined主库实现以最长行的长度为准遍历因此较短的行在缺失位置会以undefined传给iteratee。这一行为在 src/array/unzipWith.spec.ts 中有明确测试it(should handle arrays of different lengths, () { const zipped zip([1, 20, 300, 4000], [100, 200, 300]); const result unzipWith(zipped, (item, item2, item3, item4) item item2 item3 item4); expect(result).toEqual([4321, NaN]); });在这个用例中第二行只有 3 个元素第 3 列下标 3缺失item4为undefined导致300 undefined得到NaN。在实际业务中通常需要在iteratee内对undefined做防御例如(a || 0) (b || 0)这在主库文档 docs/reference/array/unzipWith.md 中有相应示例。2. 空数组输入当输入为空数组[]时主库实现中Math.max(0, ...[])得到0循环不会执行返回空数组[]。这一行为同样有测试覆盖it(should return an empty array when given an empty array, () { const result unzipWith([], (...items: number[]) items.reduce((sum, value) sum value, 0)); expect(result).toEqual([]); });需要说明的是主库文档 docs/reference/array/unzipWith.md 中记载传入空数组会抛出错误而当前仓库源码src/array/unzipWith.ts的实际行为是返回空数组——两者存在出入从测试证据看返回空数组是当前实现的真实行为文档所述可能在后续版本中调整。若你的代码依赖这一行为建议以实际运行结果为准。3. 与 zip 的互逆关系unzipWith常与zip配合使用先用zip把多个数组按位置打包成组再用unzipWith拆开并聚合。上面行长度不一致的测试正是先zip再unzipWith的完整链路。这种组合在 fp 变体中同样成立——es-toolkit/fp同时导出了 unzip.tssrc/fp/array/unzip.ts与 unzipWith.ts它们都通过 src/fp/array/index.ts 统一导出可从es-toolkit/fp直接引入。六、实战组合在数据流水线中使用 unzipWith由于 fp 变体的返回值是一个等待数据的函数它可以自由嵌入pipe流水线的任意位置与其他操作符衔接。一个更完整的场景先zip多组数据再unzipWith聚合最后继续交给后续操作符处理。import { pipe, unzipWith, map } from es-toolkit/fp; // 三组学生的成绩按列聚合为平均分后再放大 10 倍 const scores [ [80, 90], [85, 95], [75, 88], ]; const result pipe( scores, unzipWith((a, b, c) (a b c) / 3), // [80, 91] map(avg avg * 10) // [800, 910] );这种写法的优势在于每一步变换从上到下顺序阅读无需像嵌套调用那样从内向外解析也无需在步骤之间声明临时变量。这与 docs/fp/intro.md 中描述的 fp 设计理念一致——用pipe表达数据变换替代嵌套调用与临时变量。需要注意unzipWith本身不是惰性lazy操作符它必须完整读取整个二维数组才能确定最长行长度并完成聚合因此在pipe中它会作为普通非 lazy步骤执行。这与map、filter、take等可惰性融合的操作符不同pipe的实现在 src/fp/pipe.ts 中通过chunkFunctions将连续函数分组、对惰性函数做融合处理而unzipWith会走逐个应用的普通路径。七、快速参考项目说明导入路径import { unzipWith } from es-toolkit/fp;签名unzipWithT, R(iteratee: (...args: T[]) R): (target: readonly T[][]) R[]iteratee接收同一位置的多个值返回合并结果返回值一个 contenteditable="false">【免费下载链接】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),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。