You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:10:31