1

This is my first post here. I'm new to Javascript and here's my problem:

I have four input fields in html. All the four input fields are not necessary to be filled by the user; one would be enough. Now my question is how to get the average of the inputs whether the user has given me only one filled field or 2 or 3 or even four of them filled.

Here's my starting code but there's a problem with it.

function calculateAll() {
    //first create an array to gather inputs from user and create the sum

    var listening_avg_array = new Array();
    listening_avg_array[0] = parseInt(listeningInput1_js.value);
    listening_avg_array[1] = parseInt(listeningInput2_js.value);
    listening_avg_array[2] = parseInt(listeningInput3_js.value);
    listening_avg_array[3] = parseInt(listeningInput4_js.value);

    //now we calculate the average for listening scores
    var sum = 0;
    for (var i = 0; i < listening_avg_array.length; i++) {
        sum += listening_avg_array[i];
    }

    var avg = sum / listening_avg_array.length;

    listening_avg_span_js.innerHTML = avg;
}

Unfortunately I get a "NaN" error if the user has given me only 3 or less inputs; But if the user gives me all the four inputs the code works, but it's only one of the possible conditions. Sometimes I may only get 2 fields from the user and I have to get the average by dividing the sum by 2.

I don't know how to do it.

And here's the html:

<input id="listening-input1" type="number" min="60" max="100">
<input id="listening-input2" type="number" min="60" max="100">
<input id="listening-input3" type="number" min="60" max="100">
<input id="listening-input4" type="number" min="60" max="100">

3 Answers3

3

You could filter the inputs that contain NaN to get an array of set values:

const values = listening_avg_array.filter(value => !isNaN(value));

So then you can sum that up and divide it by its length:

const average = values.reduce((a, b) => a + b, 0) / values.length;

or if you prefer a good old for loop:

var sum = 0, count = 0;
for (const value of listening_avg_array) {
    if(!isNaN(value)) {
        sum += value;
        count++;
    }
}

const average = sum / count;
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • 1
    Wouldn't that be wrong? (e.g. user entered 3 numbers, he'll calculate the avg by diving by 4) – Haytam Jul 07 '18 at 11:38
1

You could omit the array and take the value directly after checking the value for an empty string or a NaN value. BTW, '' is not NaN, but a real value, which is not a number after converting.

function calculateAll() {
    var i, count = 0, sum = 0, temp;
    for (var i = 1; i <= 4; i++) {
        temp = document.getElementById('listening-input' + i).value;
        if (temp === '' || isNaN(temp)) continue;
        sum += +temp;
        count++;
    }
    document.getElementById('average').innerHTML = count ? sum / count : 'No values';
}
<input id="listening-input1" type="number" min="60" max="100" onchange="calculateAll()">
<input id="listening-input2" type="number" min="60" max="100" onchange="calculateAll()">
<input id="listening-input3" type="number" min="60" max="100" onchange="calculateAll()">
<input id="listening-input4" type="number" min="60" max="100" onchange="calculateAll()"><br>
Average: <span id="average"></span>
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • It did the job in the shortest way. Thanks. – abouzar zanganeh Jul 07 '18 at 12:14
  • Could you interpret this part of your code for me?: `code` innerHTML = count ? sum / count : 'No values'; – abouzar zanganeh Jul 07 '18 at 13:56
  • sorry for the delay, it uses the [conditional (ternary) operator `?:`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) which has a check and returns either the first part or the second. it's like `if` for expressions. – Nina Scholz Jul 07 '18 at 16:32
0

If the inputs aren't treated individually somewhere else, using class instead of id is a better approach, and makes code short.

document.getElementById('calculate').addEventListener('click', function(e) {
  calculateAll();
});

function calculateAll() {
  let sum = 0, count = 0;
  const inputs = document.querySelectorAll('.listening-input');
  inputs.forEach(function(el) {
    if(!el.value) return;
    sum += parseInt(el.value);
    count++;
  });
  const avg = sum / count;
  console.log(avg);
}
<input class="listening-input" type="number" min="60" max="100">
<input class="listening-input" type="number" min="60" max="100">
<input class="listening-input" type="number" min="60" max="100">
<input class="listening-input" type="number" min="60" max="100">

<button id="calculate">calculate</button>
Hikmat G.
  • 2,591
  • 1
  • 20
  • 40