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

如何将含重复邮箱的对象数组分组到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);

代码说明

  1. 预分组邮箱:先把相同邮箱的对象归集到一起,方便后续批量分配
  2. 循环构建分组:每次新建一个分组,从每个剩余的邮箱分组中取一个对象加入,直到组满或无可用邮箱
  3. 维护分组唯一性:添加对象前检查当前组是否已有该邮箱的对象,保证每组内邮箱不重复
  4. 清理空分组:当某个邮箱的所有对象都分配完毕后,从预分组中移除,避免重复处理

这个实现逻辑清晰,能准确满足需求,且易于维护和扩展。

内容的提问来源于stack exchange,提问作者abdeljalil ait etaleb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 07:40:37