Javascript - How to calculate average data in an array with multiple objects and return in another array

Asked

Viewed 2,009 times

2

Having an array notasAlunos, as a small example:

notasAlunos = [
 { matricula: "117", nome: "Joao", materia: "x1", nota: 78 },
 { matricula: "117" nome: "Joao", materia: "x8", nota: 80 },
 { matricula: "117", nome: "Joao", materia: "y5", nota: 48 },
 { matricula: "119", nome: "Pedro", materia: "w2", nota: 69 },
 { matricula: "119" nome: "Pedro", materia: "x2", nota: 90 },
 { matricula: "132", nome: "Joana" materia: "v3", nota: 77 },
 { matricula:"132" nome: "Joana", materia: "w2", nota: 76 } 
]

I would like to get as return the following array:

MediaNotasAluno = [
 { matricula: "117", media: 68,66},
 { matricula: "119", media: 79,50},
 { matricula "132", media: 76,50} 
]

Attempted code:

var MediaNotasAluno = []
    var total = 0;
    for (var i = 0; i < notasAlunos.length; i++) {
        total += notasAlunos[i].nota
        var avg = total / notasAlunos[i].nota.lenght
        MediaNotasAluno.push({notasAlunos.matricula, avg})
    }
  • 1

    Tried to make some code? what was your effort?

  • I tried, but unsuccessfully, see an example: var mediaNotasAlunos = [] var total = 0; for (var i = 0; i < notasAlunos.length; i++) { total += notasAlunos[i]. note var avg = total / notasAlunos[i].nota.lenght mediaNotasAlunos.push({notasAlunos[.matricula, avg}) }

  • You can edit the question and insert the code you tried to do into it. But by the array of objects in the posted example, it will not even run its attempt, pq, the property name and the property matter has invalid characters. It would have to be string.

  • all fields are string except note that is int. I had not posted correctly. Thank you.

  • It helped a lot, the two answers work perfectly. Thank you.

2 answers

5


The problem is that you’re adding up all the students' grades, and you’re also dividing by the amount of grades in the middle of the loop (which doesn’t make sense, because to calculate the average you should only divide after adding up all the notes - that is, it should be outside the for, not inside him).

And if you want to average each student, you have to calculate several different totals (one for each enrollment). And the division can only be made at the end, after you added everything (and not within the for).

One way to do this is to store the totals of each student and the respective number of grades in an object. Then you calculate the average for each one:

let notasAlunos = [
 { matricula: "117", nome: "Joao", materia: "x1", nota: 78 },
 { matricula: "117", nome: "Joao", materia: "x8", nota: 80 },
 { matricula: "117", nome: "Joao", materia: "y5", nota: 48 },
 { matricula: "119", nome: "Pedro", materia: "w2", nota: 69 },
 { matricula: "119", nome: "Pedro", materia: "x2", nota: 90 },
 { matricula: "132", nome: "Joana", materia: "v3", nota: 77 },
 { matricula: "132", nome: "Joana", materia: "w2", nota: 76 } 
];

// calcula a soma das notas de cada aluno (e também a quantidade de notas para cada um)
let MediaNotasAluno = {};
for (let notaAluno of notasAlunos) {
    // se ainda não tem registro para esta matrícula, cria um novo 
    if (! MediaNotasAluno[notaAluno.matricula]) {
        MediaNotasAluno[notaAluno.matricula] = {
            'matricula': notaAluno.matricula, 'total': 0, 'qtd': 0
        };
    }
    // atualiza o total e a quantidade de notas
    MediaNotasAluno[notaAluno.matricula].total += notaAluno.nota;
    MediaNotasAluno[notaAluno.matricula].qtd++;
}

// tendo o total e a quantidade, calcula a média para cada um
// cria um array com os valores
MediaNotasAluno = Object.values(MediaNotasAluno);
for (let m of MediaNotasAluno) {
    m.media = m.total / m.qtd;
    // apaga a quantidade e o total, pois não preciso mais
    delete m['qtd'];
    delete m['total'];
}
console.log(MediaNotasAluno);

In the first for i create an object containing the registrations, and for each one I add the notes and update the amount of notes. After this first loop, the object will be like this:

{
  '117': { matricula: '117', total: 206, qtd: 3 },
  '119': { matricula: '119', total: 159, qtd: 2 },
  '132': { matricula: '132', total: 153, qtd: 2 }
}

But as you want an array, just take the values of the object, using Object.values.

Then in the second for i use the total and quantity to calculate the average (and then erase the total and quantity as I will not need more). The result will be:

[
  { matricula: '117', media: 68.66666666666667 },
  { matricula: '119', media: 79.5 },
  { matricula: '132', media: 76.5 }
]

If you want to round the values to have only two decimal places, you can change the calculation to:

for (let m of MediaNotasAluno) {
    m.media = Math.floor(100 * m.total / m.qtd) / 100;
    delete m['qtd'];
    delete m['total'];
}

So the first average will be 68.66.

3

You can do it like this:

const notasAlunos = [
 { matricula: "117", nome: "Joao", materia: "x1", nota: 78 },
 { matricula: "117", nome: "Joao", materia: "x8", nota: 80 },
 { matricula: "117", nome: "Joao", materia: "y5", nota: 48 },
 { matricula: "119", nome: "Pedro", materia: "w2", nota: 69 },
 { matricula: "119", nome: "Pedro", materia: "x2", nota: 90 },
 { matricula: "132", nome: "Joana", materia: "v3", nota: 77 },
 { matricula:"132", nome: "Joana", materia: "w2", nota: 76 } 
]

const acum = [];

notasAlunos.forEach(aluno => {
  const match = acum.find(media => media.matricula === aluno.matricula);
  if (match) {
    match.soma += aluno.nota
    match.notas++;
  } else {
    aluno.soma = aluno.nota
    aluno.notas = 1;
    acum.push(aluno)
  }
});

const medias = [].map.call(acum, i => ({matricula: i.matricula, media: i.soma / i.notas}))

console.log(medias);

Use an array to record the number of notes and the total sum.

Then generate the array with each student’s average (sum/Qtd).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.