I have an array of objects ( responses
), which can contain any number of objects (ie 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.
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; }
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; }
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};
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.