如何用JavaScript合并同ID对象,生成对应小时的时间数组?
问题描述
我有一组包含id和time(小时数值)的对象数组,尝试遍历每个对象生成对应24小时的数组:匹配小时则填入对应time值,否则填0。但当前代码会为每个对象生成新条目,无法合并相同id的结果。
当前代码
let formatted = []; const results = [ { id: "id1", time: 4 }, { id: "id1", time: 5 }, { id: "id2", time: 1 }, { id: "id2", time: 15 }, { id: "id2", time: 12 }, { id: "id3", time: 6 }, { id: "id3", time: 8 }, ]; const hours = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, ]; results.forEach((result) => { let hourArr = []; hours.forEach((hour) => { hourArr.push(result.time == hour ? hour : 0); }); formatted.push({ id: result.id, time: hourArr }); }); console.log(formatted);
当前输出
[ { id: "id1", time: [ 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], }, { id: "id1", time: [ 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], }, { id: "id2", time: [ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], }, { id: "id2", time: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, ], }, { id: "id2", time: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], }, { id: "id3", time: [ 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], }, { id: "id3", time: [ 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], }, ];
期望输出
将相同id的对象合并,生成一个包含24小时的数组,对应小时位置填入该id的time值,其余为0:
[ { id: "id1", time: [ 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], }, { id: "id2", time: [ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, ], }, { id: "id3", time: [ 0, 0, 0, 0, 0, 0, 6, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], }, ];
解决方案
核心思路是先按id聚合同一id的所有time值,再为每个id生成完整的24小时数组,或者直接在遍历过程中维护每个id的结果数组。
方法一:先分组再生成结果
const results = [ { id: "id1", time: 4 }, { id: "id1", time: 5 }, { id: "id2", time: 1 }, { id: "id2", time: 15 }, { id: "id2", time: 12 }, { id: "id3", time: 6 }, { id: "id3", time: 8 }, ]; const hours = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]; // 按id分组,收集每个id对应的所有time值 const groupedData = {}; results.forEach(item => { if (!groupedData[item.id]) { groupedData[item.id] = []; } groupedData[item.id].push(item.time); }); // 为每个分组生成24小时数组 const formatted = Object.entries(groupedData).map(([id, times]) => { const timeArr = hours.map(hour => times.includes(hour) ? hour : 0); return { id, time: timeArr }; }); console.log(formatted);
方法二:用reduce一步完成(更高效)
const results = [ { id: "id1", time: 4 }, { id: "id1", time: 5 }, { id: "id2", time: 1 }, { id: "id2", time: 15 }, { id: "id2", time: 12 }, { id: "id3", time: 6 }, { id: "id3", time: 8 }, ]; const formatted = results.reduce((acc, item) => { // 查找当前id是否已存在于结果数组中 const existingEntry = acc.find(entry => entry.id === item.id); if (existingEntry) { // 存在则直接更新对应小时的位置 existingEntry.time[item.time] = item.time; } else { // 不存在则初始化全0数组,再设置对应小时值 const timeArr = new Array(24).fill(0); timeArr[item.time] = item.time; acc.push({ id: item.id, time: timeArr }); } return acc; }, []); console.log(formatted);
代码说明
- 方法一先通过对象完成分组,再遍历分组数据生成结果,逻辑清晰易读;
- 方法二利用
reduce直接在遍历原数组时维护结果数组,减少一次遍历操作,性能更优,适合数据量较大的场景。
内容的提问来源于stack exchange,提问作者Irving Real
相关产品推荐
相关产品推荐

