-1

I have data with value like so:

let data = [
        {
            "id": "A",
            "year": "2019",
            "score": 105.38
        },
        {
            "id": "A",
            "year": "2020",
            "score": 91.8
        },
        {
            "id": "B",
            "year": "2020",
            "score": 104.18
        },
        {
            "nip": "B",
            "year": "2019",
            "score": 101.31
        },
        {
            "id": "C",
            "year": "2020",
            "score": 91.8
        },
        {
            "id": "C",
            "year": "2019",
            "score": 106.6
        }
        ]

I want to calculate the average score for each id so the result would be something like this:

let result = [{"id": A, "average":143.89}, {"id":B, "average":154.83}, {"id":C, "average":99.2}]

How do I do that?

2 Answers2

1

You need to go through the array remembering the sum and count of entries you've seen per ID, then you can build your result array with the average (sum / count) for each ID, something like this:

const countsAndSums = new Map();
for (const {id, score} of data) {
    const entry = countsAndSums.get(id);
    if (!entry) {
        // Haven't seen this ID before
        countsAndSums.set(id, {id, count: 1, sum: score});
    } else {
        // Update the count and sum for this ID
        ++entry.count;
        entry.sum += score;
    }
}

// Now you can build the array
const result = [...countsAndSums.values()].map(({id, count, sum}) => ({id, average: sum / count}));

Live Example:

let data = [
    {
        "id": "A",
        "year": "2019",
        "score": 105.38
    },
    {
        "id": "A",
        "year": "2020",
        "score": 91.8
    },
    {
        "id": "B",
        "year": "2020",
        "score": 104.18
    },
    {
        "nip": "B",
        "year": "2019",
        "score": 101.31
    },
    {
        "id": "C",
        "year": "2020",
        "score": 91.8
    },
    {
        "id": "C",
        "year": "2019",
        "score": 106.6
    }
];

const countsAndSums = new Map();
for (const {id, score} of data) {
    const entry = countsAndSums.get(id);
    if (!entry) {
        // Haven't seen this ID before
        countsAndSums.set(id, {id, count: 1, sum: score});
    } else {
        // Update the count and sum for this ID
        ++entry.count;
        entry.sum += score;
    }
}

// Now you can build the array
const result = [...countsAndSums.values()].map(({id, count, sum}) => ({id, average: sum / count}));
console.log(result);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

Here's a convoluted one-liner solution:

let data = [
    {
        "id": "A",
        "year": "2019",
        "score": 105.38
    },
    {
        "id": "A",
        "year": "2020",
        "score": 91.8
    },
    {
        "id": "B",
        "year": "2020",
        "score": 104.18
    },
    {
        "id": "B",
        "year": "2019",
        "score": 101.31
    },
    {
        "id": "C",
        "year": "2020",
        "score": 91.8
    },
    {
        "id": "C",
        "year": "2019",
        "score": 106.6
    }
];

const averages = Object.entries(data.reduce((acc, { id, score }) => ({ ...acc, [id]: [...(acc[id] || []), score] }), {}))
  .map(([id, scores]) => ({ id, average: scores.reduce((acc, cur) => acc + cur, 0) / scores.length }));

console.log(averages);
Hao Wu
  • 17,573
  • 6
  • 28
  • 60