如何迭代嵌套数组对象,整理地点维度的客户状态统计数据?
嵌套数组的地点统计重构
你有如下的嵌套对象数组(先修正了原代码里的语法错误,比如缺冒号、逗号):
let array = [ { key: 'Newcastle', values: [ { key: 'ID1000', values: [ {name: 'Jeff', cust_id: "ID1000", status: 'sold'}, {name: 'Jeff', cust_id: "ID1000", status: 'pending'}, ] }, { key: 'ID2000', values: [ {name: 'Bob', cust_id: "ID2000", status: 'sold'} ] } ] }, { key: 'London', values: [ { key: 'ID3000', values: [ {name: 'Gary', cust_id: "ID3000", status: 'sold'}, ] }, { key: 'ID4000', values: [ {name: 'Mary', cust_id: "ID4000", status: 'interest'}, {name: 'Mary', cust_id: "ID4000", status: 'interest'}, {name: 'Mary', cust_id: "ID4000", status: 'pending'}, ] } ] } ];
你希望将其重构为按地点统计客户数及各状态次数的格式:
[ {Location: 'Newcastle', customers: 2, sold: 2, pending: 1, interest: 0}, {Location: 'London', customers: 2, sold: 1, pending: 1, interest: 2} ]
你当前尝试的代码遇到了问题,比如forEach无法正确返回统计值,多层嵌套循环导致计数混乱:
function transform(array) { let arr = [] array.forEach(function(x) { function soldCount() { x.values.forEach(function(x) { let sold = x.values.forEach(function(x) { let soldTrue = 0 if (x.status === "sold") { soldTrue++ } console.log(soldTrue) if (soldTrue > 0) { return soldTrue } }) }) } let obj = { location: x.key, customers: x.values.length, sold: soldCount() } arr.push(obj) }) return arr }
问题分析
你的核心问题在于:
forEach本身不返回任何值(默认返回undefined),所以你在soldCount里用forEach尝试返回计数是行不通的;- 嵌套
forEach里的变量作用域有问题,每次循环都会重置soldTrue,根本无法实现累加; - 只单独处理了
sold状态,没有统一的逻辑去统计pending和interest,扩展性差。
解决方案:用reduce+map实现高效统计
reduce是处理这类累加统计场景的最优工具,结合map可以快速把每个地点转换为我们需要的统计对象。下面是完整的实现:
function transform(array) { return array.map(locationItem => { // 初始化当前地点的统计模板 const stats = { Location: locationItem.key, customers: locationItem.values.length, sold: 0, pending: 0, interest: 0 }; // 遍历每个客户的所有订单,累加状态计数 locationItem.values.forEach(customer => { customer.values.forEach(order => { // 只要状态是我们定义的类型,就对应累加 if (stats.hasOwnProperty(order.status)) { stats[order.status]++; } }); }); return stats; }); } // 测试执行 const result = transform(array); console.log(result);
代码解释
- 外层
map:遍历每个地点对象,把每个地点直接转换为目标统计格式; - 初始化统计对象:先填好地点名称、客户数(直接取
values的长度,因为每个元素对应一个独立客户),并把三个状态的初始计数设为0; - 嵌套遍历订单:先遍历每个客户的订单数组,再遍历每个订单,根据订单的
status字段,对应累加统计对象里的计数; - 返回统计结果:每个地点处理完成后,把统计对象加入最终结果数组。
如果想让代码更紧凑,也可以用嵌套reduce来替代forEach,逻辑是完全一致的:
function transform(array) { return array.map(locationItem => { // 用reduce累加所有订单的状态计数 const statusStats = locationItem.values.reduce((total, customer) => { return customer.values.reduce((counts, order) => { counts[order.status]++; return counts; }, total); }, { sold: 0, pending: 0, interest: 0 }); // 合并基础信息和状态统计 return { Location: locationItem.key, customers: locationItem.values.length, ...statusStats }; }); }
这个版本用reduce的累加特性来统计状态次数,最后用对象展开运算符...把状态统计和基础信息合并,代码更简洁。
内容的提问来源于stack exchange,提问作者Sorvah
相关产品推荐
相关产品推荐

