简体   繁体   中英

How to group and sum values from array of objects?

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:

  • 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.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM