如何正确匹配users与contactInfo数组:解决姓名匹配错误问题
问题场景
当users数组中存在多个姓氏(last_name)相同的用户对象,而contactInfo数组中对应姓氏的联系人对象数量不同时,现有代码会出现匹配错误。例如users里有两个姓氏为Howell的用户,但contactInfo中只有一个Ervin Howell的联系人,现有代码会错误地将该联系人信息关联给Patricia Howell。
需求目标
将users数组与contactInfo数组进行匹配,需遵循以下规则:
- 当用户姓氏在
users数组中无重复时,按姓氏(last_name)匹配联系人; - 当用户姓氏在
users数组中存在重复时,改为按名字(first_name)+姓氏组合匹配,确保唯一关联。
现有实现代码
let users = [ { "id": 1, "first_name": "Leanne", "last_name": "Graham", "username": "Leanne.Graham" }, { "id": 2, "first_name": "Ervin", "last_name": "Howell", "username": "Ervin.Howell" }, { "id": 3, "first_name": "Clementine", "last_name": "Bauch", "username": "Clementine.Bauch" }, { "id": 4, "first_name": "Patricia", "last_name": "Howell", "username": "Patricia.Howell" }, { "id": 5, "first_name": "Patricia", "last_name": "Lebsack", "username": "Patricia.Lebsack" }, { "id": 6, "first_name": "Chelsey", "last_name": "Dietrich", "username": "Chelsey.Dietrich" }, { "id": 7, "first_name": "Dennis", "last_name": "Schulist", "username": "Dennis.Schulist" }, { "id": 8, "first_name": "Kurtis", "last_name": "Weissnat", "username": "Kurtis.Weissnat" }, { "id": 9, "first_name": "Nicholas", "last_name": "Runolfsdottir", "username": "Nicholas.Runolfsdottir" }, { "id": 10, "first_name": "Glenna", "last_name": "Reichert", "username": "Glenna.Reichert" }, { "id": 11, "first_name": "Clementina", "last_name": "DuBuque", "username": "Clementina.DuBuque" }, { "id": 12, "first_name": "Dani", "last_name": "Reichert", "username": "Dani.Reichert" }, ]; let contactInfo = [ { "first_name": "Leanne", "last_name": "Graham", "email": "Leanne@Graham.biz", "phone": "1-770-736-8031 x56442", "website": "LeanneGraham.org" }, { "first_name": "Ervin", "last_name": "Howell", "email": "Ervin@Howell.tv", "phone": "010-692-6593 x09125", "website": "ErvinHowell.net" }, { "first_name": "Clementine", "last_name": "Bauch", "email": "Clementine@Bauch.net", "phone": "1-463-123-4447", "website": "ClementineBauch.info" }, { "first_name": "Patricia", "last_name": "Lebsack", "email": "Patricia@Lebsack.org", "phone": "493-170-9623 x156", "website": "PatriciaLebsack.biz" }, { "first_name": "Chelsey", "last_name": "Dietrich", "email": "Chelsey@Dietrich.ca", "phone": "(254)954-1289", "website": "ChelseyDietrich.info" }, { "first_name": "Dennis", "last_name": "Schulist", "email": "Dennis@Schulist.info", "phone": "1-477-935-8478 x6430", "website": "DennisSchulist.org" }, { "first_name": "Kurtis", "last_name": "Weissnat", "email": "Kurtis@Weissnat.biz", "phone": "210.067.6132", "website": "KurtisWeissnat.io" }, { "first_name": "Nicholas", "last_name": "Runolfsdottir", "email": "Nicholas@Runolfsdottir.me", "phone": "586.493.6943 x140", "website": "NicholasRunolfsdottir.com" }, { "first_name": "Glenna", "last_name": "Reichert", "email": "Glenna@Reichert.io", "phone": "(775)976-6794 x41206", "website": "GlennaReichert.com" }, { "first_name": "Dani", "last_name": "Reichert", "email": "Dani@Reichert.io", "phone": "(775)976-6794 x41206", "website": "DaniReichert.com" }, { "first_name": "Clementina", "last_name": "DuBuque", "email": "Clementina@DuBuque.biz", "phone": "024-648-3804", "website": "ClementinaDuBuque.net" } ]; let usersArray = []; for(let el of users) { let obj1 = []; for(let val of contactInfo) { if(el.last_name == val.last_name) { obj1.push(val); } } if(obj1.length > 1) { let contactDup = obj1; for(let val of contactDup) { if(el.first_name == val.first_name) { let contact = val; let obj = Object.assign(el, contact); usersArray.push(obj); } } } else { let contact = obj1[0]; let obj = Object.assign(el, contact); usersArray.push(obj); } } console.log('usersArray', usersArray);
问题排查
现有代码的核心错误在于判断逻辑的依据错误:
- 原代码通过
contactInfo中当前用户姓氏对应的联系人数量来决定匹配方式,而不是根据users数组中当前用户姓氏的重复数量; - 例如
users中有2个Howell用户,但contactInfo中只有1个Howell联系人,原代码会进入else分支直接按姓氏匹配,导致Patricia Howell错误关联Ervin Howell的联系人信息; - 此外,
Object.assign(el, contact)会直接修改原users数组中的对象,造成原数据污染。
修正后的代码
let users = [ { "id": 1, "first_name": "Leanne", "last_name": "Graham", "username": "Leanne.Graham" }, { "id": 2, "first_name": "Ervin", "last_name": "Howell", "username": "Ervin.Howell" }, { "id": 3, "first_name": "Clementine", "last_name": "Bauch", "username": "Clementine.Bauch" }, { "id": 4, "first_name": "Patricia", "last_name": "Howell", "username": "Patricia.Howell" }, { "id": 5, "first_name": "Patricia", "last_name": "Lebsack", "username": "Patricia.Lebsack" }, { "id": 6, "first_name": "Chelsey", "last_name": "Dietrich", "username": "Chelsey.Dietrich" }, { "id": 7, "first_name": "Dennis", "last_name": "Schulist", "username": "Dennis.Schulist" }, { "id": 8, "first_name": "Kurtis", "last_name": "Weissnat", "username": "Kurtis.Weissnat" }, { "id": 9, "first_name": "Nicholas", "last_name": "Runolfsdottir", "username": "Nicholas.Runolfsdottir" }, { "id": 10, "first_name": "Glenna", "last_name": "Reichert", "username": "Glenna.Reichert" }, { "id": 11, "first_name": "Clementina", "last_name": "DuBuque", "username": "Clementina.DuBuque" }, { "id": 12, "first_name": "Dani", "last_name": "Reichert", "username": "Dani.Reichert" }, ]; let contactInfo = [ { "first_name": "Leanne", "last_name": "Graham", "email": "Leanne@Graham.biz", "phone": "1-770-736-8031 x56442", "website": "LeanneGraham.org" }, { "first_name": "Ervin", "last_name": "Howell", "email": "Ervin@Howell.tv", "phone": "010-692-6593 x09125", "website": "ErvinHowell.net" }, { "first_name": "Clementine", "last_name": "Bauch", "email": "Clementine@Bauch.net", "phone": "1-463-123-4447", "website": "ClementineBauch.info" }, { "first_name": "Patricia", "last_name": "Lebsack", "email": "Patricia@Lebsack.org", "phone": "493-170-9623 x156", "website": "PatriciaLebsack.biz" }, { "first_name": "Chelsey", "last_name": "Dietrich", "email": "Chelsey@Dietrich.ca", "phone": "(254)954-1289", "website": "ChelseyDietrich.info" }, { "first_name": "Dennis", "last_name": "Schulist", "email": "Dennis@Schulist.info", "phone": "1-477-935-8478 x6430", "website": "DennisSchulist.org" }, { "first_name": "Kurtis", "last_name": "Weissnat", "email": "Kurtis@Weissnat.biz", "phone": "210.067.6132", "website": "KurtisWeissnat.io" }, { "first_name": "Nicholas", "last_name": "Runolfsdottir", "email": "Nicholas@Runolfsdottir.me", "phone": "586.493.6943 x140", "website": "NicholasRunolfsdottir.com" }, { "first_name": "Glenna", "last_name": "Reichert", "email": "Glenna@Reichert.io", "phone": "(775)976-6794 x41206", "website": "GlennaReichert.com" }, { "first_name": "Dani", "last_name": "Reichert", "email": "Dani@Reichert.io", "phone": "(775)976-6794 x41206", "website": "DaniReichert.com" }, { "first_name": "Clementina", "last_name": "DuBuque", "email": "Clementina@DuBuque.biz", "phone": "024-648-3804", "website": "ClementinaDuBuque.net" } ]; // 统计users数组中每个姓氏的出现次数 const lastNameCount = users.reduce((countMap, user) => { countMap[user.last_name] = (countMap[user.last_name] || 0) + 1; return countMap; }, {}); // 创建contactInfo的索引表,优化匹配效率 const contactIndex = contactInfo.reduce((indexMap, contact) => { // 用全名作为键,确保唯一匹配 const fullName = `${contact.first_name}_${contact.last_name}`; indexMap[fullName] = contact; // 保留姓氏索引,用于无重复姓氏的匹配 if (!indexMap[contact.last_name]) { indexMap[contact.last_name] = contact; } return indexMap; }, {}); const usersArray = users.map(user => { let matchedContact; const hasDuplicateLastName = lastNameCount[user.last_name] > 1; if (hasDuplicateLastName) { // 姓氏重复时,按全名匹配 const fullName = `${user.first_name}_${user.last_name}`; matchedContact = contactIndex[fullName]; } else { // 姓氏无重复时,按姓氏匹配 matchedContact = contactIndex[user.last_name]; } // 返回新对象,避免修改原users数组 return matchedContact ? {...user, ...matchedContact} : {...user}; }); console.log('usersArray', usersArray);
修正逻辑说明
- 统计姓氏重复次数:通过
reduce遍历users数组,生成每个姓氏的出现次数映射表,以此判断是否需要切换匹配规则; - 创建联系人索引:提前将
contactInfo转换为索引表,用全名(first_name+last_name)和姓氏作为键,大幅提升匹配效率; - 匹配逻辑修正:
- 若当前用户姓氏在
users中重复,使用全名精确匹配联系人; - 若姓氏无重复,直接用姓氏匹配联系人;
- 若当前用户姓氏在
- 避免原数据污染:使用展开运算符
{...user, ...matchedContact}创建新对象,不修改原users数组中的数据。
内容的提问来源于stack exchange,提问作者Abdur Raziq Khan
相关产品推荐
相关产品推荐

