How can I further optimize student average coding challenge?
For a real-world code review, code should be correct, maintainable, robust, reasonably efficient, and, most important, readable.
For your coding challenge, as you requested, I promoted efficiency to be the most important criterion.
I revised your code by simplifying code, stripping out extraneous code, minimizing loops, and improving the accuracy of the results.
- Encapsulate the solution in a function.
- Simplify by using simple loops.
- Use the same loops for totals summation and subject summation and low average.
- The order of an average, sum/n, and a sum is the same, we don't need to calculate sum/n.
- At the end, we already have the student marks sum, so simply subtract the low average mark for the returned total.
You use JavaScript IEEE 64-bit floating-point numbers and falsely assume that, for all subjects where the average SUM(mark)/students is equal, that SUM(mark/students) will be exactly equal. IEEE floating-point fractional values are an approximation. For an example, see the Floating-Point Approximation Error section at the end of this answer.
Using JSBench.me, your code is about 87% slower than my revised code.
Here is my revised version of your code:
'use strict';
function totalMarks(N, M, students) {
let totals = Array(N).fill(0);
let lowIndex = 0, lowValue = Number.MAX_VALUE;
for (let i = 0; i < M; i++) {
let subject = 0;
for (let j = 0; j < N; j++) {
let mark = students[j][i];
subject += mark;
totals[j] += mark;
}
if (lowValue > subject) {
lowIndex = i, lowValue = subject;
}
}
for (let i = 0; i < N; i++) {
totals[i]-= students[i][lowIndex];
}
return totals;
}
// data
const students = [
[75, 76, 65, 87, 87],
[78, 76, 68, 56, 89],
[67, 87, 78, 77, 65]
];
const N = students.length, M = students[0].length;
// benchmark
totalMarks(N, M, students);
// test
console.log(students);
console.log(totalMarks(N, M, students)); // => [ 325, 299, 296 ]
Floating-Point Approximation Error
In this example, we sum the all the elements of the same array, sum1 for indexes 0 to 9, sum2, in reverse order, for indexes 9 to 0. The sums, sum1 and sum2, are not exactly equal due to floating-point rounding error.
'use strict';
function floatingpointApproximation() {
let f = Array(10);
f[0] = 0.0;
for (let i = 1; i < f.length; i++) {
f[i] = 1 / i;
}
console.log(f);
let sum1 = 0;
for (let i = 0; i < f.length; i++) {
sum1 += f[i];
}
console.log("sum1", sum1);
let sum2 = 0;
for (let i = f.length - 1; i >= 0 ; i--) {
sum2 += f[i];
}
console.log("sum2", sum2);
console.log("sum1 === sum2", sum1 === sum2);
}
floatingpointApproximation();
$ node floaterr.js
f: [
0,
1,
0.5,
0.3333333333333333,
0.25,
0.2,
0.16666666666666666,
0.14285714285714285,
0.125,
0.1111111111111111
]
sum1: 2.8289682539682537
sum2: 2.828968253968254
sum1 === sum2: false
$
What Every Computer Scientist Should Know About Floating-Point Arithmetic