如何修复ES6 reduce按产品求和的结构问题并校验容量限制
产品容量求和与限制校验的实现问题
原始数据与需求
输入数据
// 二维产品数组 const products = [ [{product: "a", volume: 3}, {product: "b", volume: 7}, {product: "c", volume: 5}], [{product: "a", volume: 8}, {product: "b", volume: 10}, {product: "c", volume: 4}] ]; // 产品容量限制 const ProductLimits: ProductVolumes[] = [ {product: "a", volume: 10}, {product: "b", volume: 22}, {product: "c", volume: 12} ];
需求
- 将二维产品数组扁平化后,按产品名称对
volume求和 - 确保每个产品的总容量不超过
ProductLimits中对应的限制值
当前实现问题
已通过flatMap将二维数组扁平化,得到一维数组:
[ {product: "a", volume: 3}, {product: "b", volume: 7}, {product: "c", volume: 5}, {product: "a", volume: 8}, {product: "b", volume: 10}, {product: "c", volume: 4} ]
但后续使用reduce求和时,因初始值结构错误,导致结果异常:
// 错误的reduce实现与接口 interface IInterface { product: string; volume: number; [product: string]: any; } products.flatMap(x => x.map(y => ({ product: y.product, volume: y.volume }))) .reduce((acc: IInterface, i) => { acc[i.product] = (acc[i.product] || 0) + i.volume; return acc; });
迭代3次后得到异常结构:
product: "a" volume: 3 b: 7 c: 5
问题根因:reduce未显式指定初始值时,默认取数组第一个元素作为初始累加器,且IInterface的设计错误——不需要固定的product和volume属性,应该是纯索引签名的对象,用来存储每个产品的总容量。
修复方案
步骤1:修正reduce初始值与接口
将IInterface改为纯索引签名的对象,同时给reduce指定空对象作为初始值:
// 修正后的接口:存储产品名到总容量的映射 interface ProductTotalMap { [productName: string]: number; } const productTotals = products.flatMap(group => group) .reduce((acc: ProductTotalMap, item) => { acc[item.product] = (acc[item.product] || 0) + item.volume; return acc; }, {} as ProductTotalMap);
此时得到正确的求和结果:
{ a: 11, b: 17, c: 9 }
步骤2:添加容量限制校验
先将ProductLimits转换为对象映射,方便快速查找限制值,再遍历求和结果进行校验:
// 将限制数组转为对象映射 const limitMap = ProductLimits.reduce((map, limit) => { map[limit.product] = limit.volume; return map; }, {} as ProductTotalMap); // 校验每个产品的总容量是否超过限制 const validatedTotals = Object.entries(productTotals).map(([product, total]) => { const maxVolume = limitMap[product]; return { product, totalVolume: total, maxVolume, isOverLimit: total > maxVolume }; });
最终校验结果示例:
[ { product: "a", totalVolume: 11, maxVolume: 10, isOverLimit: true }, { product: "b", totalVolume: 17, maxVolume: 22, isOverLimit: false }, { product: "c", totalVolume: 9, maxVolume: 12, isOverLimit: false } ]
更优实现(一步完成求和与校验)
可以合并扁平化、求和、校验逻辑,减少中间变量:
const limitMap = ProductLimits.reduce((map, item) => { map[item.product] = item.volume; return map; }, {} as Record<string, number>); const result = products.flat() .reduce((acc, item) => { // 累加容量 const currentTotal = (acc[item.product]?.totalVolume || 0) + item.volume; // 对比限制 acc[item.product] = { product: item.product, totalVolume: currentTotal, maxVolume: limitMap[item.product], isOverLimit: currentTotal > limitMap[item.product] }; return acc; }, {} as Record<string, { product: string; totalVolume: number; maxVolume: number; isOverLimit: boolean }>); // 转为数组格式(可选) const resultArray = Object.values(result);
内容的提问来源于stack exchange,提问作者user3775501
相关产品推荐
相关产品推荐

