如何合并JSON响应多列表相同条目并检测用户双向互投匹配对
问题:检测用户双向投票匹配对
需要处理一个JSON响应,找出所有votedPositive的双向匹配对——即A投票给B,同时B也投票给A的用户ID组合。
给定的JSON结构:
const participants = { "data": [ { "userId": 2, "votedPositive": [ { "userId": 1 } ] }, { "userId": 3, "votedPositive": [ { "userId": 5 } ] }, { "userId": 4, "votedPositive": [] }, { "userId": 5, "votedPositive": [ { "userId": 2 }, { "userId": 3 } ] }, { "userId": 6, "votedPositive": [] }, { "userId": 7, "votedPositive": [] }, { "userId": 8, "votedPositive": [] }, { "userId": 9, "votedPositive": [] }, { "userId": 10, "votedPositive": [] }, { "userId": 11, "votedPositive": [] }, { "userId": 12, "votedPositive": [] }, { "userId": 1, "votedPositive": [ { "userId": 2 } ] } ] }
预期输出是双向匹配对列表,比如[[1,2], [3,5]]。
已编写的部分代码:
var participantsList = []; for (var index = 0; index < participants.length; index++) { for (var i = 0; i < participants[index]["votedPositive"].length; i++) { participantsList.push([participants[index]["userId"], participants[index]["votedPositive"][i]["userId"]]) } } for (var index = 0; index < participantsList.length; index++) { participantsList[index].sort(function (a, b) { return a - b; }); }
当前运行后得到的结果:
[ [ 1, 2 ], [ 3, 5 ], [ 2, 5 ], [ 3, 5 ], [ 1, 2 ] ]
现在的困惑:不确定当前代码是否正确,且不知道如何过滤重复组合,得到最终的双向匹配对列表。
解决方案
先修正原代码的小错误
原代码里participants.length是错误的,因为participants是包含data数组的对象,正确遍历对象应该是participants.data.length,否则会无法获取到用户数据。
高效的双向匹配检测方法
比起先收集所有投票对再去重,更高效的方式是先建立用户投票的映射表,直接检测双向关系,同时避免重复记录:
// 第一步:建立用户ID到其投票对象的映射 const voteMap = new Map(); participants.data.forEach(user => { // 提取当前用户投票的所有userId,转为集合方便快速查找 const votedIds = new Set(user.votedPositive.map(item => item.userId)); voteMap.set(user.userId, votedIds); }); // 第二步:找出双向匹配对,同时避免重复添加(比如[1,2]和[2,1]只存一次) const mutualMatches = new Set(); participants.data.forEach(user => { const userId = user.userId; user.votedPositive.forEach(voted => { const votedId = voted.userId; // 只处理userId < votedId的情况,防止重复 if (userId < votedId) { // 检查对方是否也投了当前用户 if (voteMap.get(votedId)?.has(userId)) { mutualMatches.add(`${userId},${votedId}`); } } }); }); // 把集合转为数组格式的最终结果 const result = Array.from(mutualMatches).map(str => str.split(',').map(Number)); console.log(result); // 输出 [[1,2], [3,5]]
基于现有代码的后续处理
如果你想基于已有的participantsList继续处理,可以统计每个排序后数组的出现次数,只保留出现次数≥2的组合:
// 修正原代码的遍历对象 var participantsList = []; for (var index = 0; index < participants.data.length; index++) { for (var i = 0; i < participants.data[index]["votedPositive"].length; i++) { participantsList.push([participants.data[index]["userId"], participants.data[index]["votedPositive"][i]["userId"]]) } } // 排序每个投票对 for (var index = 0; index < participantsList.length; index++) { participantsList[index].sort(function (a, b) { return a - b; }); } // 统计每个组合的出现次数 const countMap = {}; participantsList.forEach(pair => { const key = pair.join(','); countMap[key] = (countMap[key] || 0) + 1; }); // 过滤出出现次数≥2的组合,转为数组 const finalResult = Object.keys(countMap) .filter(key => countMap[key] >= 2) .map(key => key.split(',').map(Number)); console.log(finalResult); // 输出 [[1,2], [3,5]]
两种方法对比
- 映射表方法:时间复杂度更低,仅需两次遍历,适合数据量大的场景,同时天然避免重复记录。
- 统计次数方法:逻辑简单,无需大幅改动原有代码,适合小数据量场景。
内容的提问来源于stack exchange,提问作者Marcel Dz
相关产品推荐
相关产品推荐

