如何结合reduce与filter查找多维数组中指定字段的重复项?
用reduce+filter实现无嵌套循环的多维数组重复项筛选
给定以下多维数组:
let a = [ // Line # Vendor Proj Amount Description [ '1', '213e', '2300', '456.09', 'for gutter cleaning'], [ '2', '3334', '3321', '321.10', 'for upkeep'], [ '3', '213e', '2300', '456.09', 'for mowing'] ]
需求是筛选出Vendor(索引1)、Proj(索引2)、Amount(索引3)完全相同的元素,且不能用嵌套循环,同时希望结合reduce和filter实现,甚至自定义类似reduceFilter的方法。
方案一:标准reduce+filter组合实现
不需要自定义方法,先通过reduce统计每个目标组合的出现次数,再用filter筛选出重复项,全程无嵌套循环:
// 第一步:用reduce统计每个(Vendor, Proj, Amount)组合的出现次数 const countMap = a.reduce((map, item) => { // 生成唯一标识键:把三个目标字段拼接成字符串 const key = `${item[1]}|${item[2]}|${item[3]}`; map[key] = (map[key] || 0) + 1; return map; }, {}); // 第二步:用filter筛选出出现次数>1的元素 const dupes = a.filter(item => { const key = `${item[1]}|${item[2]}|${item[3]}`; return countMap[key] > 1; }); console.log(dupes); // 输出结果: // [ // ['1','213e','2300','456.09','for gutter cleaning'], // ['3','213e','2300','456.09','for mowing'] // ]
注:你给出的预期结果里第二个元素的Line#写成了1,这是笔误,实际原数组第三个元素的Line#是3,上面代码输出的是正确结果。
方案二:自定义Array.prototype.reduceFilter方法
如果想要像你示例里那样直接调用reduceFilter,可以给数组原型扩展这个方法,内部封装上面的reduce+filter逻辑:
// 自定义reduceFilter方法 Array.prototype.reduceFilter = function(getDuplicateKey) { // 先用reduce统计重复项的标识 const keyMap = this.reduce((map, item) => { const key = getDuplicateKey(item); map[key] = (map[key] || 0) + 1; return map; }, {}); // 再filter出重复项 return this.filter(item => { const key = getDuplicateKey(item); return keyMap[key] > 1; }); }; // 使用方式:传入一个函数,返回用于判断重复的唯一键 const dupes = a.reduceFilter(item => `${item[1]}|${item[2]}|${item[3]}`); console.log(dupes); // 输出和方案一一致
如果想要完全贴近你示例里的“两两比较当前和下一个元素”的参数形式,其实不太合理——因为reduce是累计处理逻辑,不是两两遍历比较。上面的自定义方法是更实用的实现,既满足了链式调用的简洁性,又实现了无嵌套循环的重复项筛选。
内容的提问来源于stack exchange,提问作者Travis Heeter
相关产品推荐
相关产品推荐

