如何用JavaScript/React按月份分组数组并计算每月金额总和
动态按月份分组并计算支出总和的实现方案
需求说明
我有一个包含多个对象的数组,每个对象包含date、amount、id字段,希望将所有对象按月份分组后返回每个月amount的总和。目前手动定义每个月起止日期的实现方式不够灵活,想要更动态的方案,满足以下需求:
- 获取每个月的起止日期
- 不使用lodash(可使用moment.js)按月份分组数组
- 计算每个月的金额总和
- 返回月份名称及对应总和
示例数据结构
"expenses": [ { "amount": 5.97, "date": "09/01/2022", "id": 1 }, { "amount": 12.5, "date": "11/15/2022", "id": 2 }, { "amount": 8.3, "date": "11/20/2022", "id": 3 }, { "amount": 20.0, "date": "12/05/2022", "id": 4 } ]
实现方案
使用moment.js处理日期,通过遍历数组完成分组与求和,最后动态渲染结果:
- 解析日期并生成分组标识:用moment将
date字段解析为日期对象,生成YYYY-MM格式的键作为分组依据,同时提取月份名称。 - 分组并累加金额:遍历expenses数组,以月份键为索引,累加对应月份的amount总和。
- 动态渲染组件:将分组后的结果转换为数组,循环生成对应的Card组件。
完整React组件代码
import React from 'react'; import moment from 'moment'; import { Box, Card } from '@mui/material'; const MonthsTotal = ({ expenses }) => { const monthlyTotals = {}; expenses.forEach(item => { // 解析MM/DD/YYYY格式的日期 const date = moment(item.date, 'MM/DD/YYYY'); const monthKey = date.format('YYYY-MM'); const monthName = date.format('MMMM'); // 初始化或累加对应月份的金额 if (!monthlyTotals[monthKey]) { monthlyTotals[monthKey] = { name: monthName, total: 0 }; } monthlyTotals[monthKey].total += item.amount; // 保留两位小数处理精度问题 monthlyTotals[monthKey].total = parseFloat(monthlyTotals[monthKey].total.toFixed(2)); }); // 将对象转为数组并按月份先后排序 const sortedMonths = Object.values(monthlyTotals).sort((a, b) => moment(a.name, 'MMMM').valueOf() - moment(b.name, 'MMMM').valueOf() ); return ( <> {sortedMonths.map((month, index) => ( <Box key={index} style={{ margin: '10px 0' }}> <Card variant="outlined"> <div>{month.name}</div> <div>${month.total}</div> </Card> </Box> ))} </> ); }; export default MonthsTotal;
关键说明
- 无需手动定义月份起止日期,moment.js会自动处理不同月份的天数差异(如2月、30天的月份等)。
YYYY-MM的分组键可区分同月份不同年份的数据,支持跨年场景。- 排序逻辑保证月份按时间顺序展示,避免乱序。
toFixed(2)解决浮点数累加的精度误差问题。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

