合并并去重含数组的复杂对象数组:分数合并问题
问题分析与解决方案
你的思路方向是对的,但现有代码存在几个关键问题,导致没达到预期效果:
- 调用方式错误:
_.uniqBy是函数,应该用圆括号()调用,而不是方括号[],比如_.uniqBy(merged, 'gameId')才是正确写法。 - 未处理字段命名差异:arr2中FireNormal的
_score、_playerName等带下划线的字段没有转换为标准字段名,直接合并会导致结构不一致。 - 嵌套数组去重逻辑缺失:
_.uniqBy(merged, '_scores')无法处理嵌套的_scores数组内的重复条目,因为它只会比较整个_scores数组的引用,而不是数组内的具体对象内容。
步骤1:处理字段名转换
先遍历arr2,将所有带下划线的字段转换为标准字段名,同时兼容原有格式:
const processedArr2 = arr2.map(item => { return { ...item, _scores: item._scores.map(score => { return { score: score._score ?? score.score, playerName: score._playerName ?? score.playerName, fullCombo: score._fullCombo ?? score.fullCombo, timestamp: score._timestamp ?? score.timestamp }; }) }; });
这里用空值合并运算符??确保不管字段有没有下划线,都能正确映射到标准字段名。
步骤2:合并数组并按gameId分组
使用lodash的_.groupBy将arr1和处理后的arr2合并,按gameId归类:
const combined = [...arr1, ...processedArr2]; const grouped = _.groupBy(combined, 'gameId');
步骤3:合并_scores并去重
对每个分组内的_scores数组进行合并,然后根据score、playerName、fullCombo、timestamp的组合进行去重(这四个字段完全一致才算重复条目):
const mergedArray = Object.values(grouped).map(group => { // 合并当前gameId下的所有_scores条目 const allScores = group.flatMap(item => item._scores); // 用字段组合的字符串作为唯一标识去重 const uniqueScores = _.uniqBy(allScores, score => JSON.stringify([score.score, score.playerName, score.fullCombo, score.timestamp]) ); return { gameId: group[0].gameId, _scores: uniqueScores }; });
完整可运行代码
把所有步骤整合起来:
const arr1 = [{ "gameId": "AirNormal", "_scores": [{ "score": 144701, "playerName": "FOO", "fullCombo": true, "timestamp": 1599968866 }] }, { "gameId": "EarthNormal", "_scores": [{ "score": 177352, "playerName": "BAR", "fullCombo": true, "timestamp": 1599969253 }, { "score": 164665, "playerName": "FOO", "fullCombo": false, "timestamp": 1599970971 }] }]; const arr2 = [{ "gameId": "EarthNormal", "_scores": [{ "score": 177352, "playerName": "BASH", "fullCombo": false, "timestamp": 1512969017 }, { "score": 164665, "playerName": "FOO", "fullCombo": false, "timestamp": 1599970971 }] }, { "gameId": "FireNormal", "_scores": [{ "_score": 124701, "_playerName": "FOO", "_fullCombo": true, "_timestamp": 1591954866 }] }]; // 处理arr2的字段名转换 const processedArr2 = arr2.map(item => { return { ...item, _scores: item._scores.map(score => { return { score: score._score ?? score.score, playerName: score._playerName ?? score.playerName, fullCombo: score._fullCombo ?? score.fullCombo, timestamp: score._timestamp ?? score.timestamp }; }) }; }); // 合并并分组 const combined = [...arr1, ...processedArr2]; const grouped = _.groupBy(combined, 'gameId'); // 合并scores并去重得到最终结果 const mergedArray = Object.values(grouped).map(group => { const allScores = group.flatMap(item => item._scores); const uniqueScores = _.uniqBy(allScores, score => JSON.stringify([score.score, score.playerName, score.fullCombo, score.timestamp]) ); return { gameId: group[0].gameId, _scores: uniqueScores }; }); console.log(mergedArray);
运行这段代码就能得到你预期的合并结果。
内容的提问来源于stack exchange,提问作者Joey
相关产品推荐
相关产品推荐

