
本文详细介绍了如何利用 javascript 的 `reduce` 方法将一个扁平的对象数组转换为具有多层级分组和数据聚合的复杂结构。通过逐层查找和创建新对象,我们能够高效地根据 `medico`、`rateio` 和 `convenio` 字段对数据进行归类并汇总 `subtotal`,从而实现灵活的数据重构。
引言
在现代Web开发中,数据处理是日常任务之一。我们经常需要将从后端获取的扁平化数据转换为更具结构化、便于前端展示或进一步处理的复杂形式。JavaScript 提供了多种数组方法来完成这类转换,其中 reduce 方法以其强大的聚合能力,在处理多层级分组和数据汇总场景时表现尤为出色。本教程将深入探讨如何利用 reduce 方法,将一个包含多个对象的数组,根据特定字段进行多层级嵌套分组,并对数值型字段进行累加。
场景描述:数据转换需求
假设我们有一个原始的销售明细数组 arr,其中每个对象包含 medico(医生)、rateio(费率)、convenio(协议)和 subtotal(小计)等信息:
const arr = [ { medico: "med1", rateio: "rat1", convenio: "conv1", subtotal: 10 }, { medico: "med2", rateio: "rat2", convenio: "conv2", subtotal: 10 }, { medico: "med2", rateio: "rat2", convenio: "conv2", subtotal: 20 }, { medico: "med1", rateio: "rat1", convenio: "conv3", subtotal: 20 }, { medico: "med1", rateio: "rat1", convenio: "conv3", subtotal: 25 }, { medico: "med2", rateio: "rat3", convenio: "conv4", subtotal: 15 }, { medico: 'med2', rateio: 'rat4', convenio: 'conv3', subtotal: 10 },];
我们的目标是将这个数组转换为一个按 medico、rateio 和 convenio 逐级分组的嵌套结构,并且在最内层对 subtotal 进行求和,最终结构如下所示:
const result = [ {medico: "med1", grantotals:[ { rateio: "rat1", grandtotals: [ { convenio: "conv1", sum_subtotal: 10 }, { convenio: "conv3", sum_subtotal: 45 } ] } ]}, {medico: "med2", grantotals:[ { rateio: "rat2", grandtotals: [ { convenio: "conv2", sum_subtotal: 30 }, ] }, { rateio: "rat3", grandtotals: [ { convenio: "conv4", sum_subtotal: 15 }, ] }, { rateio: "rat4", grandtotals: [ { convenio: "conv3", sum_subtotal: 10 }, ] } ]}];
使用 reduce 方法实现转换
reduce() 方法对数组中的每个元素执行一个由您提供的 reducer 函数,将其结果汇总为单个返回值。它接收两个参数:一个 reducer 函数和一个可选的 initialValue。reducer 函数又接收四个参数:accumulator(累加器)、currentValue(当前值)、currentIndex(当前索引)和 array(源数组)。在这个场景中,我们将 accumulator 初始化为一个空数组 [],它将逐步构建最终的嵌套结构。
立即学习“Java免费学习笔记(深入)”;
核心逻辑
转换的核心思想是:遍历原始数组的每个对象,对于每个对象,我们都需要检查目标结构中是否已存在对应的 medico、rateio 和 convenio 层级。如果存在,则更新其 subtotal;如果不存在,则创建相应的层级和对象。
const result = arr.reduce((acc, obj) => { // 1. 查找或创建 medico 层级 let existingMedico = acc.find((item) => item.medico === obj.medico); if (!existingMedico) { existingMedico = { medico: obj.medico, grantotals: [] }; acc.push(existingMedico); } // 2. 查找或创建 rateio 层级 let existingRateio = existingMedico.grantotals.find( (item) => item.rateio === obj.rateio ); if (!existingRateio) { existingRateio = { rateio: obj.rateio, grandtotals: [] }; existingMedico.grantotals.push(existingRateio); } // 3. 查找或创建 convenio 层级并累加 subtotal let existingConvenio = existingRateio.grandtotals.find( (item) => item.convenio === obj.convenio ); if (existingConvenio) { existingConvenio.sum_subtotal += obj.subtotal; } else { existingRateio.grandtotals.push({ convenio: obj.convenio, sum_subtotal: obj.subtotal, }); } return acc;}, []); // 初始累加器为一个空数组console.log(result);
代码解析
上述代码通过 reduce 方法逐步构建了目标结构。具体步骤如下:
初始化累加器 (acc): reduce 方法的第二个参数 [] 将 acc 初始化为一个空数组,它将存储最终的医生(medico)列表。遍历每个原始对象 (obj): 对于 arr 中的每一个元素 obj:处理 medico 层级:使用 acc.find() 检查当前 obj.medico 是否已存在于 acc 中。如果不存在 (!existingMedico),则创建一个新的 medico 对象,包含 medico 字段和空的 grantotals 数组,并将其添加到 acc 中。无论是否存在,existingMedico 都会指向当前 medico 对应的对象。处理 rateio 层级:在 existingMedico.grantotals 数组中,使用 find() 检查当前 obj.rateio 是否已存在。如果不存在 (!existingRateio),则创建一个新的 rateio 对象,包含 rateio 字段和空的 grandtotals 数组,并将其添加到 existingMedico.grantotals 中。existingRateio 指向当前 rateio 对应的对象。处理 convenio 层级并累加 subtotal:在 existingRateio.grandtotals 数组中,使用 find() 检查当前 obj.convenio 是否已存在。如果存在 (existingConvenio),则直接将 obj.subtotal 加到 existingConvenio.sum_subtotal 上。如果不存在,则创建一个新的 convenio 对象,包含 convenio 字段和 obj.subtotal 作为 sum_subtotal,并将其添加到 existingRateio.grandtotals 中。返回累加器: 每次迭代结束后,reduce 方法会返回更新后的 acc,作为下一次迭代的累加器。
注意事项与优化
性能考量: 在上述实现中,我们使用了 Array.prototype.find() 方法进行查找。find() 方法的时间复杂度为 O(N),这意味着在每一层级查找现有元素时,最坏情况下都需要遍历该层级的整个数组。如果原始数组 arr 非常大,并且 medico、rateio、`conven
以上就是JavaScript reduce 方法实现多层级对象数组的聚合与转换的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1538122.html
微信扫一扫
支付宝扫一扫