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.
- The average scores of each subject of each student (Expected output:)
[{student: "A", english: 75, maths: 70},
{student: "B", english: 50, maths: 55}]
- 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; }