如何用reduce实现相同月份数据求和聚合以生成图表?
Got it, let's work through this problem together! You're on the right track using reduce—it's perfect for grouping and aggregating data like this. The key part is setting up an accumulator to track totals per month, then handling the logic to either add to an existing month's total or create a new entry for it.
First, let's address a small detail
Notice that your number values are stored as strings. If we don't convert them to numbers first, we'll end up with string concatenation (like "260"+"320" becoming "260320" instead of 580) — so we'll fix that right away.
Here's the complete working code
const rawData = [ { "indessx": "1", "type": "A", "number": "260", "month": "May", "date": "01/05/20" }, { "indessx": "2", "type": "A", "number": "320", "month": "May", "date": "02/05/20" }, { "indessx": "2", "type": "A", "number": "320", "month": "June", "date": "02/06/20" } ]; // Use reduce to build monthly totals, then convert the result to an array const aggregatedData = Object.values(rawData.reduce((acc, currentItem) => { const month = currentItem.month; const numericNumber = parseInt(currentItem.number, 10); // Check if this month already exists in our accumulator if (acc[month]) { // If yes, add the current number to the existing total acc[month].number += numericNumber; } else { // If no, create a new entry with the current item's data (and converted number) acc[month] = { ...currentItem, number: numericNumber }; } return acc; }, {})); console.log(aggregatedData);
Let's break down what's happening here:
- Accumulator Setup: We start with an empty object
{}as the initial value forreduce—this will hold our monthly totals, with month names as keys. - Loop Through Each Item: For every entry in your raw data:
- We grab the month and convert the string
numberto an integer. - If the month is already a key in the accumulator, we add the current number to that entry's total.
- If it's not, we create a new entry using the item's existing fields (via the spread operator
...currentItem) but replace the stringnumberwith our converted integer.
- We grab the month and convert the string
- Convert Object to Array:
Object.values()takes the accumulator object (where keys are months) and turns it into the final array of aggregated objects.
The output you'll get:
[ { indessx: '1', type: 'A', number: 580, month: 'May', date: '01/05/20' }, { indessx: '2', type: 'A', number: 320, month: 'June', date: '02/06/20' } ]
Bonus: Simplified version (if you don't need extra fields)
If you only care about the month and total number, you can streamline the code even more:
const simplifiedAggregated = Object.entries(rawData.reduce((acc, item) => { const month = item.month; acc[month] = (acc[month] || 0) + parseInt(item.number, 10); return acc; }, {})).map(([month, number]) => ({ month, number }));
This will give you a cleaner result:
[ { month: 'May', number: 580 }, { month: 'June', number: 320 } ]
内容的提问来源于stack exchange,提问作者Rishav Sinha

