Node.js中如何按年、月两级分组对象数组?
Node.js 按年、月两级分组对象数组的实现方法
需求说明
需要将给定的对象数组按年份和月份进行两级分组,把同年同月的项归为一组,最终得到嵌套结构的分组结果。
初始数据
const items = [ {month: 11, year: 2022, amount: 10}, {month: 12, year: 2022, amount: 6}, {month: 11, year: 2022, amount: 7}, {month: 12, year: 2022, amount: 12}, {month: 1, year: 2023, amount: 5}, {month: 1, year: 2023, amount: 15}, {month: 11, year: 2023, amount: 30}, {month: 11, year: 2023, amount: 20} ];
期望结果
const result = { "2022": { "11": [ {month: 11, year: 2022, amount: 10}, {month: 11, year: 2022, amount: 7} ], "12": [ {month: 12, year: 2022, amount: 6}, {month: 12, year: 2022, amount: 12} ] }, "2023": { "11": [ {month: 11, year: 2023, amount: 30}, {month: 11, year: 2023, amount: 20} ], "1": [ {month: 1, year: 2023, amount: 5}, {month: 1, year: 2023, amount: 15} ] } };
错误原因分析
你之前尝试的方式出现问题,主要是这两个点:
- 对
Object.values(itemsPerYear)直接用groupBy:会把所有年份的数组合并成一个大数组,按月份分组后会混合同年份的同月份数据,不符合两级分组的要求。 - forEach遍历内部用groupBy返回undefined:大概率是没有将groupBy的结果正确赋值给对应的年份对象属性,导致最终结果没有被正确收集。
正确实现方法
方法1:用Array.prototype.reduce一步到位(原生无依赖)
这是最灵活且兼容性较好的方式,不需要额外依赖库,直接通过reduce构建嵌套结构:
const result = items.reduce((acc, item) => { // 确保当前年份对应的容器存在,不存在则初始化空对象 if (!acc[item.year]) { acc[item.year] = {}; } // 确保当前年份下的月份数组存在,不存在则初始化空数组 if (!acc[item.year][item.month]) { acc[item.year][item.month] = []; } // 将当前项推入对应月份的数组 acc[item.year][item.month].push(item); return acc; }, {}); console.log(result);
方法2:基于你原有的groupBy思路修正
如果你习惯用groupBy(比如lodash的groupBy或ES2024原生groupBy),可以分两步完成:
场景A:使用lodash的groupBy
const _ = require('lodash'); // 第一步:按年份分组 const itemsPerYear = _.groupBy(items, 'year'); const result = {}; // 第二步:遍历每个年份分组,再按月份分组 Object.entries(itemsPerYear).forEach(([year, yearItems]) => { result[year] = _.groupBy(yearItems, 'month'); }); console.log(result);
场景B:使用ES2024原生Array.prototype.groupBy
注意:原生groupBy返回的是Map对象,需要转成普通对象:
// 第一步:按年份分组得到Map const itemsPerYearMap = items.groupBy(item => item.year); const result = {}; // 第二步:遍历Map,对每个年份的数组按月份分组并转成对象 for (const [year, yearItems] of itemsPerYearMap) { const monthGroupMap = yearItems.groupBy(item => item.month); result[year] = Object.fromEntries(monthGroupMap); } console.log(result);
内容的提问来源于stack exchange,提问作者fedjedmedjed
相关产品推荐
相关产品推荐

