Reputation: 1590
I have an array of objects (responses
), which can contain any number of objects (i.e. indeterminate number of rounds
and questions
), in any order. The objects inside will be similar:
responses [
{
name: "personA"
uniqueId: "abcd"
roundNumber: 0
questionNumber: 0
score: 1
},
{
name: "personA"
uniqueId: "abcd"
roundNumber: 0
questionNumber: 1
score: 1
},
{
name: "personA"
uniqueId: "abcd"
roundNumber: 1
questionNumber: 0
score: 0
},
name: "personB"
uniqueId: "efgh"
roundNumber: 0
questionNumber: 0
score: 1
},
{
name: "personB"
uniqueId: "efgh"
roundNumber: 0
questionNumber: 1
score: 0
},
{
name: "personB"
uniqueId: "efgh"
roundNumber: 1
questionNumber: 0
score: 1
}
]
How would I group and sum the scores
depending on the values of the objects? More specifically I would like to take all the objects for personA
(using their name
and uniqueId
fields), then sum up the scores by roundNumber
. Then repeat the process for every player.
Example of flow:
personA
for roundNumber: 0
, and save that.personA
for roundNumber: 1
, and save that, etc...personB
, then personC
, etc...The resulting array could be something like:
sorted = [
{
name: "personA",
uniqueId: "abcd",
scores: [2, 0]
},
{
name: "personB",
uniqueId: "efgh",
scores: [1, 1]
}
]
I've looked at for loops, indexOf, map, filter, reduce, and I'm struggling hard with this one because the amount of players
, rounds
, or questions
could be any amount.
Upvotes: 1
Views: 86
Reputation: 386519
You could take a standard approach for grouping and increment the value of a certain index.
var data = [{ name: "personA", uniqueId: "abcd", roundNumber: 0, questionNumber: 0, score: 1 }, { name: "personA", uniqueId: "abcd", roundNumber: 0, questionNumber: 1, score: 1 }, { name: "personA", uniqueId: "abcd", roundNumber: 1, questionNumber: 0, score: 0 }, { name: "personB", uniqueId: "efgh", roundNumber: 0, questionNumber: 0, score: 1 }, { name: "personB", uniqueId: "efgh", roundNumber: 0, questionNumber: 1, score: 0 }, { name: "personB", uniqueId: "efgh", roundNumber: 1, questionNumber: 0, score: 1 }],
grouped = Object.values(data.reduce((r, { name, uniqueId, roundNumber, score }) => {
r[uniqueId] = r[uniqueId] || { name, uniqueId, scores: [] };
r[uniqueId].scores[roundNumber] = (r[uniqueId].scores[roundNumber] || 0) + score;
return r;
}, {}));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 2
Reputation: 2392
This solution solution runs in N (log N)
which is the most efficient thing you can do. assuming you have a lot of items in the responses array
const responses = [......];
var group = [];
responses.sort((a, b) => {
if (a.name === b.name)
return a.uniqueId < b.uniqueId;
return a.name < b.name;
}).forEach(item => {
if(group.length === 0 || group[group.length - 1].name !== item.name || group[group.length - 1].uniqueId !== item.uniqueId) {
group.push({
name: item.name,
uniqueId: item.uniqueId,
scores: { [item.roundNumber]: item.score }
})
} else {
if (group[group.length - 1].scores[item.roundNumber]) {
group[group.length - 1].scores[item.roundNumber] += item.score;
} else {
group[group.length - 1].scores[item.roundNumber] = item.score;
}
}
});
group = group.map(item => {
const scores = [];
for( const i in item.scores ) {
scores.push(item.scores[i]);
}
return {...item, scores};
});
Upvotes: 0
Reputation: 6390
You can try this with a reduce
method. Also, I make the scores
as an object with roundNumber
index which can help you to define which score gained for which round.
const responses = [{ name: "personA", uniqueId: "abcd", roundNumber: 0, questionNumber: 0, score: 1 }, { name: "personA", uniqueId: "abcd", roundNumber: 0, questionNumber: 1, score: 1 }, { name: "personA", uniqueId: "abcd", roundNumber: 1, questionNumber: 0, score: 0 }, { name: "personB", uniqueId: "efgh", roundNumber: 0, questionNumber: 0, score: 1 }, { name: "personB", uniqueId: "efgh", roundNumber: 0, questionNumber: 1, score: 0 }, { name: "personB", uniqueId: "efgh", roundNumber: 1, questionNumber: 0, score: 1 }];
const res = responses.reduce((a, c) => {
if (!a.find(x => x.name === c.name)) {
a.push({name: c.name, uniqueId: c.uniqueId, scores: {[c.roundNumber]: c.score}});
} else {
let index = a.findIndex(x => x.name === c.name);
if ( index > -1) {
a[index].scores[c.roundNumber] = (a[index].scores[c.roundNumber] || 0) + c.score;
}
}
return a;
}, []);
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0