如何将含重复邮箱的对象数组分组到Map:保留重复且每组4个唯一邮箱
分组含重复邮箱的数组,确保每组邮箱唯一且符合指定大小
需求说明
- 数组中的对象包含
email字段,存在重复邮箱记录,需保留所有重复项 - 按指定大小(如4)分组到
Map中,键格式为group-0、group-1... - 每个分组内的对象必须对应不同的邮箱,每个分组最多包含指定数量的不同邮箱对象
- 重复的邮箱记录要分配到不同的分组中,尽可能填满每个分组
原始数据
const emails = [ {userId:'someuserid',email:'email1@gmail.com',password:'password1',recovery:'recovery1@gmail.com'}, {userId:'someuserid',email:'email1@gmail.com',password:'password1',recovery:'recovery1@gmail.com'}, {userId:'someuserid',email:'email10@gmail.com',password:'password10',recovery:'recovery10@gmail.com'}, {userId:'someuserid',email:'email10@gmail.com',password:'password10',recovery:'recovery10@gmail.com'}, {userId:'someuserid',email:'email2@gmail.com',password:'password2',recovery:'recovery2@gmail.com'}, {userId:'someuserid',email:'email2@gmail.com',password:'password2',recovery:'recovery2@gmail.com'}, {userId:'someuserid',email:'email3@gmail.com',password:'password3',recovery:'recovery3@gmail.com'}, {userId:'someuserid',email:'email3@gmail.com',password:'password3',recovery:'recovery3@gmail.com'}, {userId:'someuserid',email:'email4@gmail.com',password:'password4',recovery:'recovery4@gmail.com'}, {userId:'someuserid',email:'email4@gmail.com',password:'password4',recovery:'recovery4@gmail.com'}, {userId:'someuserid',email:'email5@gmail.com',password:'password5',recovery:'recovery5@gmail.com'}, {userId:'someuserid',email:'email5@gmail.com',password:'password5',recovery:'recovery5@gmail.com'}, {userId:'someuserid',email:'email6@gmail.com',password:'password6',recovery:'recovery6@gmail.com'}, {userId:'someuserid',email:'email6@gmail.com',password:'password6',recovery:'recovery6@gmail.com'}, {userId:'someuserid',email:'email7@gmail.com',password:'password7',recovery:'recovery7@gmail.com'}, {userId:'someuserid',email:'email7@gmail.com',password:'password7',recovery:'recovery7@gmail.com'}, {userId:'someuserid',email:'email8@gmail.com',password:'password8',recovery:'recovery8@gmail.com'}, {userId:'someuserid',email:'email8@gmail.com',password:'password8',recovery:'recovery8@gmail.com'}, {userId:'someuserid',email:'email9@gmail.com',password:'password9',recovery:'recovery9@gmail.com'}, {userId:'someuserid',email:'email9@gmail.com',password:'password9',recovery:'recovery9@gmail.com'} ]
现有尝试代码
const groupsMap = new Map() let sequence = 0 let profilePrefix = 'none' let pivotPrefix = 0 const prefix = 'group' const bucketSize = 4 for (let index = 0; index < emails.length; index++) { const currentEmail = emails[index]?.email const prevEmail = emails[index - 1]?.email if (prevEmail && currentEmail === prevEmail) { if ( groupsMap.has(`${prefix}-${pivotPrefix}`) && groupsMap.get(`${prefix}-${pivotPrefix}`).length < bucketSize && groupsMap .get(`${prefix}-${pivotPrefix}`) .findIndex((email) => currentEmail === email.email) === -1 ) { groupsMap.get(`${prefix}-${pivotPrefix}`).push(emails[index]) if ( groupsMap.get(`${prefix}-${pivotPrefix}`).length === bucketSize ) { pivotPrefix++ } } else { if (pivotPrefix > 0) { const nextPivot = pivotPrefix++ groupsMap.get(`${prefix}-${nextPivot}`).push(emails[index]) } sequence++ profilePrefix = `${prefix}-${sequence}` groupsMap.set(profilePrefix, [emails[index]]) } } else { if (groupsMap.has(`${prefix}-${pivotPrefix}`)) { if ( groupsMap.get(`${prefix}-${pivotPrefix}`).length < bucketSize ) { groupsMap.get(`${prefix}-${pivotPrefix}`).push(emails[index]) if ( groupsMap.get(`${prefix}-${pivotPrefix}`).length === bucketSize ) { pivotPrefix++ } } else { sequence++ groupsMap.set(`${prefix}-${sequence}`, [emails[index]]) } } else { sequence++ pivotPrefix = sequence profilePrefix = `${prefix}-${pivotPrefix}` groupsMap.set(profilePrefix, [emails[index]]) } } } console.log(groupsMap)
期望输出
Map(6) { 'group-0' => [ { userId: 'someuserid', email: 'email1@gmail.com', password: 'password1', recovery: 'recovery1@gmail.com' }, { userId: 'someuserid', email: 'email10@gmail.com', password: 'password10', recovery: 'recovery10@gmail.com' }, { userId: 'someuserid', email: 'email2@gmail.com', password: 'password2', recovery: 'recovery2@gmail.com' }, { userId: 'someuserid', email: 'email3@gmail.com', password: 'password3', recovery: 'recovery3@gmail.com' } ], 'group-1' => [ { userId: 'someuserid', email: 'email1@gmail.com', password: 'password1', recovery: 'recovery1@gmail.com' }, { userId: 'someuserid', email: 'email10@gmail.com', password: 'password10', recovery: 'recovery10@gmail.com' }, { userId: 'someuserid', email: 'email2@gmail.com', password: 'password2', recovery: 'recovery2@gmail.com' }, { userId: 'someuserid', email: 'email3@gmail.com', password: 'password3', recovery: 'recovery3@gmail.com' } ], 'group-2' => [ { userId: 'someuserid', email: 'email4@gmail.com', password: 'password4', recovery: 'recovery4@gmail.com' }, { userId: 'someuserid', email: 'email5@gmail.com', password: 'password5', recovery: 'recovery5@gmail.com' }, { userId: 'someuserid', email: 'email6@gmail.com', password: 'password6', recovery: 'recovery6@gmail.com' }, { userId: 'someuserid', email: 'email7@gmail.com', password: 'password7', recovery: 'recovery7@gmail.com' } ], 'group-3' => [ { userId: 'someuserid', email: 'email4@gmail.com', password: 'password4', recovery: 'recovery4@gmail.com' }, { userId: 'someuserid', email: 'email5@gmail.com', password: 'password5', recovery: 'recovery5@gmail.com' }, { userId: 'someuserid', email: 'email6@gmail.com', password: 'password6', recovery: 'recovery6@gmail.com' }, { userId: 'someuserid', email: 'email7@gmail.com', password: 'password7', recovery: 'recovery7@gmail.com' } ], 'group-4' => [ { userId: 'someuserid', email: 'email8@gmail.com', password: 'password8', recovery: 'recovery8@gmail.com' }, { userId: 'someuserid', email: 'email9@gmail.com', password: 'password9', recovery: 'recovery9@gmail.com' } ], 'group-5' => [ { userId: 'someuserid', email: 'email8@gmail.com', password: 'password8', recovery: 'recovery8@gmail.com' }, { userId: 'someuserid', email: 'email9@gmail.com', password: 'password9', recovery: 'recovery9@gmail.com' } ] }
解决方案
现有代码逻辑较复杂,容易出现分组错误。下面是更清晰、可靠的实现:
function groupEmails(emails, bucketSize) { // 第一步:按邮箱归集所有重复对象 const emailGroups = new Map(); for (const emailObj of emails) { if (!emailGroups.has(emailObj.email)) { emailGroups.set(emailObj.email, []); } emailGroups.get(emailObj.email).push(emailObj); } const resultMap = new Map(); let groupIndex = 0; // 循环分配对象,直到所有邮箱的对象都处理完 while (emailGroups.size > 0) { const currentGroup = []; const emptyEmailGroups = []; // 遍历剩余邮箱分组,往当前组添加一个对象 for (const [email, objs] of emailGroups) { if (currentGroup.length >= bucketSize) break; // 确保当前组没有该邮箱的对象 if (!currentGroup.some(item => item.email === email)) { currentGroup.push(objs.shift()); // 如果该邮箱的对象已分配完,标记为待删除 if (objs.length === 0) { emptyEmailGroups.push(email); } } } // 将当前组加入结果Map resultMap.set(`group-${groupIndex}`, currentGroup); groupIndex++; // 删除已分配完的邮箱分组 for (const email of emptyEmailGroups) { emailGroups.delete(email); } } return resultMap; } // 使用示例 const bucketSize = 4; const groupsMap = groupEmails(emails, bucketSize); console.log(groupsMap);
代码说明
- 预分组邮箱:先把相同邮箱的对象归集到一起,方便后续批量分配
- 循环构建分组:每次新建一个分组,从每个剩余的邮箱分组中取一个对象加入,直到组满或无可用邮箱
- 维护分组唯一性:添加对象前检查当前组是否已有该邮箱的对象,保证每组内邮箱不重复
- 清理空分组:当某个邮箱的所有对象都分配完毕后,从预分组中移除,避免重复处理
这个实现逻辑清晰,能准确满足需求,且易于维护和扩展。
内容的提问来源于stack exchange,提问作者abdeljalil ait etaleb
相关产品推荐
相关产品推荐

