JavaScript如何按嵌套属性对对象数组进行分组?
实现按日期、名称分组并合并物品数量
原始数据
[ { "date": "08/08/2022", "name": "Swordsman", "items": [ { "item_id": 1, "item": { "item_name": "Item 1", }, "count": 1 } ] }, { "date": "08/08/2022", "name": "Swordsman", "items": [ { "item_id": 1, "item": { "item_name": "Item 1", }, "count": 2 }, { "item_id": 2, "item": { "item_name": "Item 2", }, "count": 1 } ] } ]
需求说明
需要按date和name进行分组,合并同一分组内相同item_id的物品的count值,最终输出结构如下:
[ { "date": "08/08/2022", "name": "Swordsman", "items": [ { "item_id": 1, "name": "Item 1", "count": 3 }, { "item_id": 2, "name": "Item 2", "count": 1 } ] } ]
当存在同一date不同name的情况时,需按date和name分别分组。
尝试过的代码(未得到预期结果)
const groups = data.reduce((groups, data) => { const date = data.date; if (!groups[date]) { groups[date] = []; } groups[date].push(data); return groups; }, {}); const groupArrays = Object.keys(groups).map((date) => { return { date, items: groups[date] }; });
解决方案
方法一:原生JavaScript实现
核心思路是用date + name作为分组的唯一键,先聚合所有同组数据,再对分组内的物品按item_id合并count:
const data = [/* 你的原始数据 */]; const result = Object.values(data.reduce((acc, current) => { // 生成唯一分组标识:日期+名称 const groupKey = `${current.date}_${current.name}`; if (!acc[groupKey]) { // 初始化分组结构 acc[groupKey] = { date: current.date, name: current.name, items: {} // 用对象暂存物品,便于按item_id快速查找 }; } // 遍历当前项的物品,累加count current.items.forEach(item => { const itemKey = item.item_id; if (!acc[groupKey].items[itemKey]) { acc[groupKey].items[itemKey] = { item_id: item.item_id, name: item.item.item_name, count: 0 }; } acc[groupKey].items[itemKey].count += item.count; }); return acc; }, {})).map(group => { // 将物品对象转为数组格式 group.items = Object.values(group.items); return group; }); console.log(result);
方法二:使用Lodash实现
借助_.groupBy完成基础分组,再通过数组方法合并物品的count值:
const _ = require('lodash'); const data = [/* 你的原始数据 */]; // 按日期+名称分组 const groupedData = _.groupBy(data, item => `${item.date}_${item.name}`); const result = Object.values(groupedData).map(group => { const mergedGroup = { date: group[0].date, name: group[0].name, items: [] }; // 合并所有物品并累加count mergedGroup.items = _.flatMap(group, 'items').reduce((acc, item) => { const targetItem = _.find(acc, { item_id: item.item_id }); if (targetItem) { targetItem.count += item.count; } else { acc.push({ item_id: item.item_id, name: item.item.item_name, count: item.count }); } return acc; }, []); return mergedGroup; }); console.log(result);
内容的提问来源于stack exchange,提问作者user3233787
相关产品推荐
相关产品推荐

