如何将对象数组按category和subCategory分组并统计重复项数量?
按分类嵌套分组并统计重复项次数
问题描述
现有如下对象数组:
const data = [ {labelSlug: 'cola', category: 'catering', subCategory: 'drinks', provider: 'coca cola'}, {labelSlug: 'cola', category: 'catering', subCategory: 'drinks', provider: 'coca cola'}, {labelSlug: 'fanta', category: 'catering', subCategory: 'drinks', provider: 'coca cola'}, {labelSlug: 'activities1', category: 'activities', subCategory: 'activitiesSub1', provider: 'blabla'}, {labelSlug: 'activities2', category: 'activities', subCategory: 'activitiesSub1', provider: 'blabla'}, {labelSlug: 'equipments1', category: 'equipments', subCategory: 'equipmentsSub1', provider: 'blabla'}, {labelSlug: 'equipments2', category: 'equipments', subCategory: 'equipmentsSub2', provider: 'blabla'}, {labelSlug: 'cola', category: 'catering', subCategory: 'drinks', provider: 'coca cola'}, ];
需要将其按category和subCategory嵌套分组,同时统计相同labelSlug和provider组合的出现次数,最终结构如下(注:原示例中数组嵌套键值对存在语法错误,实际应为对象嵌套):
{ "catering": { "drinks": [ { "labelSlug": "cola", "provider": "coca cola", "count": 3 }, { "labelSlug": "fanta", "provider": "coca cola", "count": 1 } ] }, "activities": { "activitiesSub1": [ { "labelSlug": "activities1", "provider": "blabla", "count": 1 }, { "labelSlug": "activities2", "provider": "blabla", "count": 1 } ] }, "equipments": { "equipmentsSub1": [ { "labelSlug": "equipments1", "provider": "blabla", "count": 1 } ], "equipmentsSub2": [ { "labelSlug": "equipments2", "provider": "blabla", "count": 1 } ] } }
尝试使用map方法实现但未成功,尝试代码如下:
const array = data.map((elem) => { const item = {}; const sub = elem.subCategory; const cat = elem.category; // i've tried many things like that just to get everything in the right place (I didnt try to get the count part yet) // item[cat[sub]].labelSlug = elem.labelSlug; // item[cat][sub].labelSlug = elem.labelSlug; // item[cat[sub.labelSlug]] = elem.labelSlug; // const item = { // [`${cat}`] : { // [`${sub}`] : { // labelSlug: elem.labelSlug // } // } // } return item; })
解决方案
map方法仅用于转换数组元素,无法实现分组聚合逻辑,应使用reduce方法来完成数据的分组和计数:
const data = [ {labelSlug: 'cola', category: 'catering', subCategory: 'drinks', provider: 'coca cola'}, {labelSlug: 'cola', category: 'catering', subCategory: 'drinks', provider: 'coca cola'}, {labelSlug: 'fanta', category: 'catering', subCategory: 'drinks', provider: 'coca cola'}, {labelSlug: 'activities1', category: 'activities', subCategory: 'activitiesSub1', provider: 'blabla'}, {labelSlug: 'activities2', category: 'activities', subCategory: 'activitiesSub1', provider: 'blabla'}, {labelSlug: 'equipments1', category: 'equipments', subCategory: 'equipmentsSub1', provider: 'blabla'}, {labelSlug: 'equipments2', category: 'equipments', subCategory: 'equipmentsSub2', provider: 'blabla'}, {labelSlug: 'cola', category: 'catering', subCategory: 'drinks', provider: 'coca cola'}, ]; const groupedData = data.reduce((acc, { labelSlug, category, subCategory, provider }) => { // 确保当前分类在累加器中存在,不存在则创建空对象 if (!acc[category]) { acc[category] = {}; } // 确保当前子分类在对应分类下存在,不存在则创建空数组用于存储统计项 if (!acc[category][subCategory]) { acc[category][subCategory] = []; } // 生成唯一标识,判断是否已存在相同的labelSlug和provider组合 const uniqueKey = `${labelSlug}-${provider}`; // 在子分类数组中查找已有项 const existingItem = acc[category][subCategory].find(item => `${item.labelSlug}-${item.provider}` === uniqueKey); if (existingItem) { // 已有项则计数加1 existingItem.count++; } else { // 无该项则添加新统计项,初始计数为1 acc[category][subCategory].push({ labelSlug, provider, count: 1 }); } return acc; }, {}); console.log(groupedData);
代码说明
- reduce聚合:
reduce接收累加器acc和当前遍历元素,逐步构建最终的分组结构。 - 层级校验:每次遍历先检查
category和subCategory对应的层级是否存在,避免访问未定义属性报错。 - 唯一标识匹配:通过
labelSlug和provider拼接成唯一键,快速判断是否已统计过该组合。 - 计数更新:找到已存在的组合则增加计数,否则添加新项并初始化计数为1。
内容的提问来源于stack exchange,提问作者Kevin Ganem
相关产品推荐
相关产品推荐

