NodeJS提取数组重复项并保留高收益对象的技术需求
解决方案:按关联组筛选最高收益对象
我明白你的需求了——你需要把所有共享mkBase或mkComp的对象归为一组,每组只保留invest.profit最高的对象,同时还要明确哪些对象被移除以及原因。之前用_.uniqBy的问题在于它只能按单一字段去重,没法处理这种跨字段的关联分组,下面是具体的实现方案:
核心思路
你的需求本质是处理连通对象组:如果两个对象共享mkBase或者mkComp,它们就属于同一个组。比如mkBase: "test"的所有对象和mkComp: "test"的所有对象会被归为一组,然后我们在每组里挑选收益最高的对象保留。
步骤1:实现关联分组(找连通分量)
首先我们需要把所有关联的对象聚合到一起,这里用一个Map来跟踪每个mkBase/mkComp对应的组,然后合并关联的组:
function groupConnectedObjects(arr) { // 记录每个标识(mkBase或mkComp)对应的组 const groupMap = new Map(); // 存储所有最终分组 const groups = []; arr.forEach(obj => { const base = obj.mkBase; const comp = obj.mkComp; // 收集当前对象关联的所有已存在的组 const relatedGroups = new Set(); if (groupMap.has(base)) relatedGroups.add(groupMap.get(base)); if (groupMap.has(comp)) relatedGroups.add(groupMap.get(comp)); if (relatedGroups.size === 0) { // 没有关联组,新建一个组 const newGroup = [obj]; groups.push(newGroup); groupMap.set(base, newGroup); groupMap.set(comp, newGroup); } else { // 合并所有关联的组,并加入当前对象 const mergedGroup = Array.from(relatedGroups).flat(); mergedGroup.push(obj); // 从groups中移除旧的分组 relatedGroups.forEach(g => { const idx = groups.indexOf(g); if (idx !== -1) groups.splice(idx, 1); }); // 添加合并后的新组 groups.push(mergedGroup); // 更新Map,让对应的标识指向新组 groupMap.set(base, mergedGroup); groupMap.set(comp, mergedGroup); } }); // 去重每组内的重复对象(避免合并时重复添加) return groups.map(group => [...new Map(group.map(item => [JSON.stringify(item), item])).values()]); }
步骤2:筛选每组最高收益对象
有了分组之后,我们可以用Lodash的_.maxBy(或者原生JS)找到每组中收益最高的对象,同时生成被移除的对象列表并附上原因:
// 确保你已经引入Lodash const _ = require('lodash'); // 你的原始数组 const arr = [ { mkBase: "test", mkComp: "test1", invest: { profit: 10 }, availability: true, option: 1 }, { mkBase: "test", mkComp: "test1", invest: { profit: 15 }, availability: false, option: 2 }, { mkBase: "test1", mkComp: "test", invest: { profit: 8 }, availability: true, option: 3 }, { mkBase: "test2", mkComp: "test", invest: { profit: 6 }, availability: true, option: 4 }, { mkBase: "test", mkComp: "test2", invest: { profit: 6 }, availability: true, option: 5 }, { mkBase: "test", mkComp: "test3", invest: { profit: 7 }, availability: true, option: 6 }, { mkBase: "test", mkComp: "test3", invest: { profit: 10 }, availability: true, option: 7 }, { mkBase: "test3", mkComp: "test4", invest: { profit: 10 }, availability: true, option: 8 } ]; // 1. 生成关联分组 const connectedGroups = groupConnectedObjects(arr); // 2. 筛选每组收益最高的对象,得到最终保留数组 const result = connectedGroups.map(group => _.maxBy(group, 'invest.profit')); // 3. 生成被移除的对象数组,并添加移除原因 const removed = arr.filter(obj => !result.includes(obj)).map(obj => { // 找到当前对象所属的组 const group = connectedGroups.find(g => g.includes(obj)); // 找到该组的最高收益对象 const maxProfitObj = _.maxBy(group, 'invest.profit'); // 生成移除原因 let reason = ''; if (obj.mkBase === maxProfitObj.mkBase) { reason = `Same Base mk as option ${maxProfitObj.option} && Profit is too low versus option ${maxProfitObj.option}`; } else if (obj.mkComp === maxProfitObj.mkComp) { reason = `Same Comp mk as option ${maxProfitObj.option} && Profit is too low versus option ${maxProfitObj.option}`; } else { reason = `Related to option ${maxProfitObj.option} (shared Base/Comp) && Profit is too low versus option ${maxProfitObj.option}`; } return { ...obj, reason }; });
验证结果
运行上述代码后,result数组会和你预期的完全一致:
[ { mkBase: "test", mkComp: "test1", invest: { profit: 15 }, availability: false, option: 2 }, { mkBase: "test1", mkComp: "test", invest: { profit: 8 }, availability: true, option: 3 }, { mkBase: "test3", mkComp: "test4", invest: { profit: 10 }, availability: true, option: 8 } ]
removed数组会包含所有被移除的对象,并且每个对象都带有你描述的移除原因,完美匹配你的需求。
为什么之前的方法无法满足需求?
你之前使用_.uniqBy只能按单一字段(mkBase或mkComp)去重,但它无法处理跨字段的关联关系——比如mkBase: "test"的对象和mkComp: "test"的对象属于同一个逻辑组,需要一起比较收益,而_.uniqBy无法识别这种关联,所以只能筛选出部分重复项,没法完成你的完整需求。
内容的提问来源于stack exchange,提问作者Martin Carre
相关产品推荐
相关产品推荐

