如何根据groupId和date为对象数组添加itemNumber键值对?
为对象数组按规则添加
itemNumber字段 问题背景
给定如下对象数组:
const data = [{ groupId:1, date:"07/10/2022", employeeName:"Jhon" }, { groupId:1, date:"07/10/2022", employeeName:"Sam" }, { groupId:2, date:"07/10/2022", employeeName:"Max" }, { groupId:1, date:"09/10/2022", employeeName:"Sabstian" }, { groupId:2, date:"09/10/2022", employeeName:"Karina" }, { groupId:2, date:"09/10/2022", employeeName:"Terry" }]
需要为每个对象添加itemNumber字段,规则如下:
- 同一
date下,itemNumber按连续数字分配;同一groupId的对象占用连续序号段,切换groupId时,基于前一个groupId的最大序号继续分配。例如07/10/2022中,groupId=1有2个对象,序号为1、2;groupId=2的对象序号从3开始。 - 不同
date的序号重新从1开始计算。
预期结果:
const data = [{ groupId:1, date:"07/10/2022", employeeName:"Jhon", itemNumber:1 }, { groupId:1, date:"07/10/2022", employeeName:"Sam", itemNumber:2 }, { groupId:2, date:"07/10/2022", employeeName:"Max", itemNumber:3 }, { groupId:1, date:"09/10/2022", employeeName:"Sabstian", itemNumber:1 }, { groupId:2, date:"09/10/2022", employeeName:"Karina", itemNumber:3 }, { groupId:2, date:"09/10/2022", employeeName:"Terry", itemNumber:4 }]
原尝试代码仅实现了按date连续分配序号,未考虑groupId的分段规则:
const expectedData = data.reduce((expectedData, item) => { const d = (expectedData[item.date] || []); d.push(item); expectedData[item.date] = d; return expectedData; }, {}); let expedctedOutputArray = [] for (var key of Object.keys(expectedData)) { expedctedOutputArray.push(expectedData[key].map((data, index) => ({...data, itemNumber:index + 1}))) } let mergedOutputArray = [].concat.apply([], expedctedOutputArray);
解决方案
要实现需求,需先按date分组,统计每个日期下各groupId的对象数量,再根据分组顺序为对象分配序号,具体代码如下:
// 第一步:按date分组,记录各groupId的对象数量、列表及出现顺序 const groupedByDate = data.reduce((acc, item) => { const dateKey = item.date; if (!acc[dateKey]) { acc[dateKey] = { groups: new Map(), // 存储groupId -> {count, items} order: [] // 记录groupId的首次出现顺序 }; } const groupInfo = acc[dateKey]; const groupId = item.groupId; if (!groupInfo.groups.has(groupId)) { groupInfo.groups.set(groupId, { count: 0, items: [] }); groupInfo.order.push(groupId); } const currentGroup = groupInfo.groups.get(groupId); currentGroup.count++; currentGroup.items.push(item); return acc; }, {}); // 第二步:为每个日期组内的对象分配itemNumber const result = []; Object.values(groupedByDate).forEach(dateGroup => { let currentStart = 1; // 按groupId的出现顺序依次处理 dateGroup.order.forEach(groupId => { const { count, items } = dateGroup.groups.get(groupId); // 为当前组的每个对象分配连续序号 items.forEach((item, idx) => { result.push({ ...item, itemNumber: currentStart + idx }); }); // 更新下一组的起始序号 currentStart += count; }); }); console.log(result);
代码说明
- 第一次
reduce完成数据分组:按date拆分数据,用Map记录每个日期下各groupId的对象数量和列表,用order数组保存groupId的首次出现顺序,保证和原始数组的顺序一致。 - 遍历每个日期组时,按
order顺序处理groupId,计算每组的起始序号后,为组内对象分配连续的itemNumber,处理完一组后更新起始序号为当前值加上该组的对象数量。 - 最终结果保留了原始数组的对象顺序,同时完全符合
itemNumber的分配规则。
内容的提问来源于stack exchange,提问作者Suraj Pawar
相关产品推荐
相关产品推荐

