Andrey Bondarev
Andrey Bondarev

Reputation: 119

Can't get average grade using reduce on an object (JavaScript)

So, long story short, I have an object with subjects and students' grades. My job is to: 1. Calculate the average for each subject. 2. Sum up all the averages; 3. Calculate the totalAverage on all subjects.

here is my code:

const grades = {
    algebra: [2,3,5,2,4,3],
    geometry: [2,4,5],
    signing: [3,3,4,5],
    physics: [5,5],
    music: [2,2,5],
    english: [4,4,3],
    poetry: [5,3,4],
    chemistry: [2],
    french: [4,4]
  }

function getAverageScore(data) {

for (let subject in data) {
    let grades = data[subject];
    let average = grades.reduce((acc,curr) => {
       return acc + curr / grades.length;

    }, 0)

For some odd reason, this doesn't work, however, when I console.log (grades.length) it shows the length of an array with grades. What am I doing wrong? Also, how can I sum all the average grades in a resulting object? Any suggestions?

Upvotes: 0

Views: 386

Answers (3)

StepUp
StepUp

Reputation: 38189

You can use reduce method to get the desired result:

const grades = {
    algebra: [2,3,5,2,4,3],
    geometry: [2,4,5],
    signing: [3,3,4,5],
    physics: [5,5],
    music: [2,2,5],
    english: [4,4,3],
    poetry: [5,3,4],
    chemistry: [2],
    french: [4,4]
};

/*
1. Calculate the average for each subject. 
2. Sum up all the averages; 
3. Calculate the totalAverage on all subjects.
*/

const avgBySubject = Object.entries(grades).reduce((a, [k, v]) => {
  a[k] = a[k] || 0;
  a[k] = v.reduce((acc, curr) => {
    acc +=curr;
    return acc;
  } ,0) / v.length;
  return a;
}, {});

console.log(`avg by subject is `, avgBySubject);

const sumAllAverages = Object.values(avgBySubject).reduce((a,c) => {
  a += c || 0;
  return a;
}, 0);

console.log(`sumAllAverages is ${sumAllAverages}`);

const theTotalAverage = sumAllAverages / Object.values(avgBySubject).length;
console.log(`theTotalAverage is: `, theTotalAverage);

Upvotes: 1

Sajal Preet Singh
Sajal Preet Singh

Reputation: 379

Here's a solution:

function getAverageScore(data) {
  const listOfSubjects = Object.keys(data);
  let averagePerSubject = {};

  let sumOfAllAverages = listOfSubjects.reduce((sumOfAllAverages, subject) => {
    let grades = data[subject];
    let average = grades.reduce((acc,curr) => (acc + curr), 0) / grades.length;

    averagePerSubject[subject] = average;
    return sumOfAllAverages + average;
  }, 0);

  let averageOfAllSubjects = sumOfAllAverages / listOfSubjects.length;

  return { averagePerSubject, sumOfAllAverages, averageOfAllSubjects };
}

The implementation though, shows the average of all subjects, not a weighted average.

Upvotes: 2

Fiszcz
Fiszcz

Reputation: 99

I have written solution for your problem:

function getAverageScore(data) {
    let sumOfAverages = 0;
    for (let subject in data) {
        const grades = data[subject];
        const sumOfGrades = grades.reduce((acc, curr) => {
            return acc + curr;
        }, 0);
        const averageOfSubject = sumOfGrades / grades.length;
        sumOfAverages += averageOfSubject;
    }
    const totalAverage = sumOfAverages / Object.keys(data).length;
    return totalAverage;
}

I think that above solution is so clear and obvious.

In your code you tried use reduce() for calculate average in wrong way. You divided every grade by number of grades (even several times, because when you add divided grade to sum of grades, you divided it in next iterations of reduce() function).

Upvotes: 0

Related Questions