Home > front end >  How to return the average of values in different objects with the same key value in an array on JS?
How to return the average of values in different objects with the same key value in an array on JS?

Time:09-04

Imagine I have an array:

let profile = [
{student: "A", english: 80, maths: 80},
{student: "A", english: 70, maths: 60},
{student: "B", english: 50, maths: 50},
{student: "B", english: "--", maths: 60},
...
]

I want to get two sets of array regarding the average.

  1. The average scores of each subject of each student (Expected output:)
[{student: "A", english: 75, maths: 70},
{student: "B", english: 50, maths: 55}]
  1. The average scores of every subject of each student (Expected output:)
[{student: "A", average: 72.5},
{student: "B", average: 53.3}]

How can I code it? Thank you very much

CodePudding user response:

I'm not sure but how did you get the average of student B to be 53.3 on the 2nd array...

Check my code below, i got 52.5 instead.

let profile = [
{student: "A", english: 80, maths: 80},
{student: "B", english: 50, maths: 50},
{student: "A", english: 70, maths: 60},
{student: "B", english: "--", maths: 60}
]


//sort by student
profile.sort((a, b) => a.student.localeCompare(b.student));


const studentsCount = profile.reduce((pre, cur, index) => {
    let find = profile.findIndex((e, _index) => _index > index && e.student === cur.student);
    if (find == -1) {
        return pre   1;
    } else return pre;
}, 0);


//stage 1
let curProfile = profile[0], startIndex, endIndex, _profile = [], maths, english, noScoreMaths, noScoreEnglish;
for (let i = 0; i < studentsCount; i  ) {
    startIndex = profile.findIndex(p => p.student === curProfile.student);
    endIndex = profile.findLastIndex(p => p.student === curProfile.student);
    noScoreMaths = 0, noScoreEnglish = 0;

    for (let j = startIndex; j <= endIndex; j  ) {
        if (isNaN(parseInt(profile[j].maths))) noScoreMaths  ;
        if (isNaN(parseInt(profile[j].english))) noScoreEnglish  ;
        
        if (j === startIndex) {
            maths = isNaN(parseInt(profile[j].maths)) ? 0 : profile[j].maths;
            english = isNaN(parseInt(profile[j].english)) ? 0 : profile[j].english;
        } else {
            maths  = isNaN(parseInt(profile[j].maths)) ? 0 : profile[j].maths;
            english  = isNaN(parseInt(profile[j].english)) ? 0 : profile[j].english;
            
            if (j === endIndex) {
                maths = parseFloat((maths / (endIndex - startIndex   1 - noScoreMaths)).toFixed(1));
                english = parseFloat((english / (endIndex - startIndex   1 - noScoreEnglish)).toFixed(1));
            }

            _profile.push({
                student: curProfile.student,
                maths,
                english
            });

            curProfile = profile[j   1];
            noScoreMaths = 0;
            noScoreEnglish = 0;
        }
    }
}

//stage 2
let __profile = [];

for (let i = 0; i < _profile.length; i  ) {
    let avgScore = parseFloat(((_profile[i].maths   _profile[i].english) / 2).toFixed(1));
    __profile.push({ student: _profile[i].student, average: avgScore });
}

console.log(_profile);
console.log(__profile);

CodePudding user response:

You could use a grouping for the students' scores and get the avarage on each subject and then get the average of each student.

const
    profile = [{ student: "A", english: 80, maths: 80 }, { student: "A", english: 70, maths: 60 }, { student: "B", english: 50, maths: 50 }, { student: "B", english: "--", maths: 60 }],
    result1 = Object
        .values(profile.reduce((r, { student, ...o }) => {
            r[student] ??= { student };
            Object
                .entries(o)
                .forEach(([k, v]) => {
                    if (isNaN(v)) return;
                    r[student][k] ??= { total: 0, count: 0 };
                    r[student][k].total  = v;
                    r[student][k].count  ;
                });
            return r;
        }, {}))
        .map(({ student, ...o }) => ({
            student,
            ...Object.fromEntries(Object.entries(o).map(([k, { total, count }]) => [k, total / count]))
        })),
    result2 = result1.map(({ student, ...o }) => {
        const values = Object.values(o);
        return {
            student,
            average: values.reduce((a, b) => a   b, 0) / values.length
        };
    });

console.log(result1);
console.log(result2);
.as-console-wrapper { max-height: 100% !important; top: 0; }

  • Related