如何用JavaScript实现按年重置的月度累计求和?
问题:年度内月度累计求和(基于JavaScript reduce)
我有一个涵盖2010至2020年的每日数据集,需要将其处理为年度内逐月累加、新年度开始时重置累计的月度总和。目前已用reduce实现月度单独求和,但未完成年度内跨月累计,寻求解决方案。
数据集示例
const data = [ {num: 3, date: "2010-01-01", month: "January", year: 2010}, {num: 10, date: "2010-01-02", month: "January", year: 2010}, {num: 2, date: "2010-01-03", month: "January", year: 2010}, {num: 0.1, date: "2010-01-04", month: "January", year: 2010}, {num: 0, date: "2010-01-05", month: "January", year: 2010}, {num: 13, date: "2010-02-01", month: "February", year: 2010}, {num: null, date: "2010-02-02", month: "February", year: 2010}, {num: null, date: "2010-02-03", month: "February", year: 2010}, {num: 2, date: "2010-02-04", month: "February", year: 2010}, {num: 3, date: "2010-02-05", month: "February", year: 2010}, {num: 0.1, date: "2010-03-01", month: "March", year: 2010}, {num: 0.002, date: "2010-03-02", month: "March", year: 2010}, {num: 4, date: "2010-03-03", month: "March", year: 2010}, {num: 4.1, date: "2010-03-04", month: "March", year: 2010}, {num: 6, date: "2010-03-05", month: "March", year: 2010}, {num: 6.7, date: "2011-01-01", month: "January", year: 2011}, {num: 2, date: "2011-01-02", month: "January", year: 2011}, {num: 2.2, date: "2011-01-03", month: "January", year: 2011}, {num: 3, date: "2011-01-04", month: "January", year: 2011}, {num: null, date: "2011-01-05", month: "January", year: 2011}, {num: 0, date: "2011-02-01", month: "February", year: 2011}, {num: 0, date: "2011-02-02", month: "February", year: 2011}, {num: 2.1, date: "2011-02-03", month: "February", year: 2011}, {num: 0, date: "2011-02-04", month: "February", year: 2011}, {num: 0, date: "2011-02-05", month: "February", year: 2011}, {num: null, date: "2011-03-01", month: "March", year: 2011}, {num: 2.1, date: "2011-03-02", month: "March", year: 2011}, {num: 4, date: "2011-03-03", month: "March", year: 2011}, {num: 9, date: "2011-03-04", month: "March", year: 2011}, {num: 7.8, date: "2011-03-05", month: "March", year: 2011}, ];
当前代码(月度单独求和)
data.reduce((acc, curr) => { if (curr.num === null ) return acc for ( const e of acc) { if (e.year === curr.year && e.month === curr.month) { e.totalSum += curr.num return acc } } const y = { year: curr.year, month: curr.month, total: curr.num } return state.concat([y]) // 此处state应为acc,属于拼写错误 }, [])
当前输出
[ {year: 2010, month: "January", total: 15.1}, {year: 2010, month: "February", total: 18}, {year: 2010, month: "March", total: 14.202}, {year: 2011, month: "January", total: 13.9}, {year: 2011, month: "February", total: 2.1 }, {year: 2011, month: "March", total: 22.9}, ]
期望输出
[ {year: 2010, month: "January", total: 15.1}, {year: 2010, month: "February", total: 33.1}, //15.1+18 {year: 2010, month: "March", total: 47.302}, //15.1+18+14.202 {year: 2011, month: "January", total: 13.9}, // 新年度重置累计 {year: 2011, month: "February", total: 16 }, // 13.9 + 2.1 {year: 2011, month: "March", total: 38.9}, //13.9 + 2.1 + 22.9 ]
解决方案
方法:分两步用reduce处理
先聚合月度单独总和,再基于此计算年度内累计值,逻辑清晰易理解,适合学习reduce的使用场景。
步骤1:修正并计算月度单独总和
先修正原代码的拼写错误,同时统一字段名,得到各年月的单独求和结果:
// 计算各月单独总和 const monthlySums = data.reduce((acc, curr) => { if (curr.num === null) return acc; // 查找当前年月已存在的条目 const existingItem = acc.find(item => item.year === curr.year && item.month === curr.month); if (existingItem) { // 累加当前数值到对应月份 existingItem.monthTotal += curr.num; } else { // 新增当月条目 acc.push({ year: curr.year, month: curr.month, monthTotal: curr.num }); } return acc; }, []);
步骤2:计算年度内累计值
遍历月度总和数组,对同一年份的条目逐月累加,新年度重置累计:
// 计算年度内累计总和 const cumulativeResult = monthlySums.reduce((acc, curr) => { // 获取上一条记录,判断是否同一年份 const lastEntry = acc[acc.length - 1]; let cumulativeTotal = curr.monthTotal; if (lastEntry && lastEntry.year === curr.year) { // 同一年份,累加上月累计值 cumulativeTotal += lastEntry.total; } acc.push({ year: curr.year, month: curr.month, total: cumulativeTotal }); return acc; }, []);
额外处理:确保数据有序
如果原始数据集的日期是乱序的,需要先按日期排序,否则月度顺序混乱会导致累计错误:
// 按日期排序(可选,若数据集已按时间顺序排列可省略) data.sort((a, b) => new Date(a.date) - new Date(b.date));
最终结果
执行上述代码后,cumulativeResult即可得到期望的年度内累计月度总和。
内容的提问来源于stack exchange,提问作者vaitaka
相关产品推荐
相关产品推荐

