I have a pretty complex problem that I can't seem to figure out. I have two array of objects that I would like to merge scores for. It should merge/append certain properties based on the scores. For example between the two arrays there are 4 total gameId
's with 3 of them being unique. When merging it should combine the _scores
section if it's the same gameId
so in this case it would be both EarthNormal
merging. But the problem is sometimes the score
in _scores
can have duplicate scores so the BAR and BASH almost look the exact same but are different it can be appended but FOO
score is the exact same on both so I don't want it merged into the scores (if that makes sense).
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
}]
}];
I would want the final merged array to look like:
mergedArray = [{
"gameId": "AirNormal",
"_scores":
[{
"score": 144701,
"playerName": "FOO",
"fullCombo": true,
"timestamp": 1599968866
}]
}, {
"gameId": "EarthNormal",
"_scores":
[{
"score": 177352,
"playerName": "BAR",
"fullCombo": true,
"timestamp": 1599969253
}, {
"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
}]
}]
I have tried doing this and using lodash
:
let merged = [...arr1, ...arr2];
merged = _.uniqBy[merged, 'gameId']
let scoresMerge = _.uniqBy[merged, '_scores']
console.log(scoresMerge);
but it didn't work as I expected. Am I approaching this incorrectly?
This is fairly straight forward using vanilla javascript.
reduce()
the merged arrays into an object indexed by gameId
_score
object against the accumulated _scores
array using .some()
and push if no match is found.Object.values()
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}]}];
const merged = Object.values([...arr1, ...arr2].reduce((a, {gameId, _scores}) => {
// retrieve gameId object otherwise initialize it.
a[gameId] = {...a[gameId] ?? {gameId, _scores: []}};
// iterate over all _score objects
_scores.forEach(s => {
// if accumulator _scores array doesn't have an object matching all properties, push _score
if (!a[gameId]['_scores'].some(o => {
return !Object.entries(s).some(([k, v]) => o[k] !== v)})
) {
a[gameId]['_scores'].push({...s});
}
});
return a;
}, {}));
console.log(merged);