1

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:

  • Sum the score of personA for roundNumber: 0, and save that.
  • Sum the score of personA for roundNumber: 1, and save that, etc...
  • Repeat for 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.

3 Answers 3

2

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; }

Sign up to request clarification or add additional context in comments.

Comments

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; }

Comments

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};
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.