如何按多字段分组对象数组并合并去重邮箱字符串?
解决按office和reportName分组并合并去重email的问题
我来帮你搞定这个分组去重的问题!你的核心需求是按office和reportName两个字段对数组分组,同时将每组内的email去重后合并为逗号分隔的字符串,原代码的问题出在email的存储方式和拼接逻辑上,下面给你详细的解决方案:
原代码的问题分析
你原来的代码里初始化email为空字符串,然后用+= o[k].split(',')来拼接,这会导致两个问题:
- 单个
email用split(',')会转成数组,和字符串相加时会直接把数组转成字符串拼接,比如两次添加amar045@gmail.com和amar0455@gmail.com,会得到amar045@gmail.comamar0455@gmail.com(没有分隔符); - 完全没有去重逻辑,重复的
email会被多次添加到结果里。
修正后的解决方案(推荐用Set去重)
利用Set天然的去重特性来存储每组的email,最后再转成逗号分隔的字符串,代码简洁且高效:
var data = [{ email: 'amar045@gmail.com', office: 'xyz.in', reportName: 'payroll', }, { email: 'amar0455@gmail.com', office: 'xyz.in', reportName: 'payroll', }, { email: 'amar0455@gmail.com', office: 'xyz.in', reportName: 'payroll', }, { email: 'amar045@gmail.com', office: 'xyz.in', reportName: 'payroll', }, { email: 'amar0445@gmail.com', office: 'yyy.in', reportName: 'delievered', }, { email: 'amar0445@gmail.com', office: 'yyy.in', reportName: 'delievered', }, { email: 'amar0425@gmail.com', office: 'yyy.in', reportName: 'payroll', }, { email: 'amar0425@gmail.com', office: 'xyz.in', reportName: 'delievered', } ]; let hash = Object.create(null); let grouped = []; data.forEach(function(o) { // 生成分组的唯一key var key = ['office', 'reportName'].map(function(k) { return o[k]; }).join('|'); // 如果当前分组不存在,初始化分组(用Set存储email实现自动去重) if (!hash[key]) { hash[key] = { office: o.office, reportName: o.reportName, email: new Set() }; grouped.push(hash[key]); } // 将当前email添加到Set中(自动忽略重复值) hash[key].email.add(o.email); }); // 把每个分组的Set转成逗号分隔的字符串 grouped.forEach(item => { item.email = Array.from(item.email).join(', '); }); console.log(grouped);
另一种方案(用数组手动判断去重)
如果你不想用Set,也可以用数组存储,添加前判断是否已存在:
var data = [{ email: 'amar045@gmail.com', office: 'xyz.in', reportName: 'payroll', }, { email: 'amar0455@gmail.com', office: 'xyz.in', reportName: 'payroll', }, { email: 'amar0455@gmail.com', office: 'xyz.in', reportName: 'payroll', }, { email: 'amar045@gmail.com', office: 'xyz.in', reportName: 'payroll', }, { email: 'amar0445@gmail.com', office: 'yyy.in', reportName: 'delievered', }, { email: 'amar0445@gmail.com', office: 'yyy.in', reportName: 'delievered', }, { email: 'amar0425@gmail.com', office: 'yyy.in', reportName: 'payroll', }, { email: 'amar0425@gmail.com', office: 'xyz.in', reportName: 'delievered', } ]; let hash = Object.create(null); let grouped = []; data.forEach(function(o) { var key = ['office', 'reportName'].map(function(k) { return o[k]; }).join('|'); if (!hash[key]) { hash[key] = { office: o.office, reportName: o.reportName, email: [] }; grouped.push(hash[key]); } // 仅当email不在数组中时才添加 if (!hash[key].email.includes(o.email)) { hash[key].email.push(o.email); } }); // 转成逗号分隔的字符串 grouped.forEach(item => { item.email = item.email.join(', '); }); console.log(grouped);
两种方案都能得到你期望的输出结果,其中Set方案在数据量大时性能更优,因为Set.add()的时间复杂度是O(1),而数组的includes()是O(n)。
内容的提问来源于stack exchange,提问作者Premjeet Kumar
相关产品推荐
相关产品推荐

