How do I fix my problem excluding 0s in my javascript? - javascript

I am trying to exclude 0 in my average code. The code is supposed to ask the user to write 4 numbers and then output an average between them 4.
The code works fine, but now I want to exclude 0s from the code, and it worked but only if you digit 0 one time. For example: I want to exclude two 0s but I have no idea how to do it. My idea was to delete the num that has 0 in it so the operation calculates the 0\> numbers only. There is my code:
var num1 = parseInt(prompt("first number: "),10);
var num2 = parseInt(prompt("second number: "),10);
var num3 = parseInt(prompt("third number: "),10);
var num4 = parseInt(prompt("fourth number: "),10);
if (num1==0){
document.getElementById("output").textContent = ((num2 + num3+ num4) / 3);
}
if (num2==0){
document.getElementById("output").textContent = ((num1 + num3+ num4) / 3);
}
if (num3==0){
document.getElementById("output").textContent = ((num1 + num2+ num4) / 3);
}
if (num4==0){
document.getElementById("output").textContent = ((num1 + num2+ num3) / 3);
}
else {
document.getElementById("output").textContent = ((num1 + num2 + num3+ num4) / 4);
}

Think about your current line of thought.
You wrote some code that averages between 3 numbers if one of the 4 numbers is zero. Now you realize it doesn't work when 2 of the 4 numbers are zeroes. How many more if-elses would you need to write to accommodate that? Then imagine if 3 of them were zeroes.
This problem is pretty simple because you only take 4 inputs. Now imagine if you took 100 inputs and are trying to get averages of all the non-zero integers from there.
A much more scalable solution would be to have it be such that no matter how many inputs you take, the code will only look at and average the non-zero integers. Something like this:
let num1 = 3; //imagine it were equivalent to var num1 = parseInt(prompt("first number: "),10);
let num2 = 4; //imagine it were equivalent to var num2 = parseInt(prompt("second number: "),10);
let num3 = 0; //imagine it were equivalent to var num3 = parseInt(prompt("third number: "),10);
let num4 = 0; //imagine it were equivalent to var num4 = parseInt(prompt("fourth number: "),10);
const numbers = [num1, num2, num3, num4]
function avgNonZeroValues(nums){
const nonZeros = nums.filter(number => number !== 0);
const avgOfNonZeros = nonZeros.reduce(
(accumulator, currentValue) => accumulator + currentValue,
0
)/nonZeros.length;
return avgOfNonZeros;
}
console.log(avgNonZeroValues(numbers));
You need to know two functions:
reduce()
Reduce is a very handy method to go through a list/array and do something with it. It takes in a initial value(0 for us), and we also tell it what to do with every element. Here, we are saying "keep on adding the elements. Here, we are using it to get the sum of all the numbers in the array.
filter()
Filter is pretty self-explanatory. You give this function an array and a condition, and it will filter out the elements that do not satisfy the condition, and will give you a new array of all the elements that do satisfy the condition. Here, we are using it to filter all the zeros out of the array.
You give this function avgNonZeroValues an array of any length containing numbers, it will remove all the 0s and average the rest of them.

Refactoring this to use arrays allows easy use of array functions to filter and transform the numbers.
const prompts = ["first", "second", "third", "fourth"];
const values = prompts
.map(p => parseInt(prompt(`${p} number: `),10))
.filter(v => v !== 0);
const total = values.reduce((acc, val) => acc + val, 0);
const avg = total/values.length;
console.log(total, avg);

Related

How to accumulate over each number? JavaScript [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
This is my problem I am having a hard time onto what to do to solve this
The Task: We'll pass you an array of two numbers.
Return the sum of those two numbers plus the
sum of all the numbers between them. The lowest number will not always come first.
For example, sumAll([4,1]) should return 10 because
sum of all the numbers between 1 and 4 (both inclusive) is 10.
function sumAll(arr) {
Math.min(arr); //finds the lowest number and takes it 1
Math.max(arr); //finds the largest number 4
//must start at the 1st number and loops over until the max value is reached
//0 start at the 0th index of the array
//++ increament by one so 1 2 3 4
//multiply's each number
//.lenght until the lenght of the array is reached
var i;
for (i = 0; i < arr.length; i++) {
i * i;
}
return 1;
}
sumAll([1, 4]);
If its going to be always 2 numbers in an array, then you can easily do this and no more fancy code.
var arr = [1, 4];
arr.sort((a, b) => a - b);
var total = 0;
for (var i = arr[0]; i <= arr[1]; i++ ) {
total += i;
}
console.log(total);
You can grab the largest number from your input array using Math.max and the smallest number from the array using Math.min, you just need to spread the values from the array into the method calls so that the numbers from the input array are used as the arguments (rather than the array itself).
Once you have the largest and smallest number, you can find the sum between (and including) these two numbers. This can be done using a loop. However, a more efficient way would be to use a formula to compute it for you. If you call the smaller number a and the larger number b, you want to find:
res = a + (a+1) + (a+2) + ... + (b-1) + b
res2 = b + (b-1) + (b-2) + ... + (a+1) + a
As you can see above res2 and res are equal. So we can say res2 = res. So, if we perform res + res2, we will get 2*res. If we add the two together (adding by the columns), we get:
2*res = a+b + (a+1)+(b-1) + (a+2)+(b-2) + ... + (b-1)+(a+1) + b+a
= a+b + a+b + a+b + ... + a+b + a+b
As you can see 2*res results in a+b being repeated for every number in the original equation, which is b-a + 1 times. Thus:
2*res = (b-a + 1)*(a+b)
As we want to find what res is, we can divide both sides by 2 to get:
res = (b-a + 1)*(a+b)/2
So, we can use the above equation to find the sum of numbers between two numbers a and b, where a is the smaller number and b is the larger number.
Using both Math.max(), Math.min() and the above equation, we can do this using the following:
const sumRange = (a, b) => ((b - a + 1)*(a + b))/2;
function sumAll(arr) {
const smaller = Math.min(...arr);
const bigger = Math.max(...arr);
return sumRange(smaller, bigger);
}
console.log(sumAll([4, 1]));
You could do this a number of ways, in this case I am using a while loop.
function sumAll(arr) {
// Get the min/max values from the array,
// Note: you have to spread the array values as individual args using '...' notation
const min = Math.min(...arr);
const max = Math.max(...arr);
// Start at the min value
let current = min;
let sum = 0;
// Loop through all numbers between min and max inclusively
while (current <= max) {
sum += current;
current++;
}
return sum;
};
console.log(sumAll([1, 4]));
You can just find the lower number before running the loop for getting the sum of all inbetween numbers.
You can just add the condition:
if(arr[0]<arr[1]){
first= arr[0], last= arr[1]
}
else {
first=arr[1], last=arr[0] }
for (i = first; i <= last; i++){
let temp = temp + i;
}
return temp;
}
Just sort the array and run the loop to add the number , starting from first element ending at second element
function findSum(arr){
let sortedArr = arr.slice().sort((a,b) => a-b);
let total =0;
for(let i=arr[0];i<=arr[1];i++){
total+=i;
}
console.log(total);
}
findSum([1,4])
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return a-b});
points[0]; // this is min value of the array values
You can check this link on w3schools

Is there a simple way to split a number into an array of digits without converting it to a string and back?

I was working on a Javascript exercise that required a number to be converted into an array of single digits and the only way I can seem to achieve this is by converting the number into a string and then converting it back to a number.
let numbers = 12345;
Array.from(numbers.toString(10), Number) // [1, 2, 3, 4, 5]
Basically, I'm wondering if this is the best way to achieve a split like this on a number or if there is a more efficient method that doesn't require such a conversion.
You can always get the smallest digit with n % 10. You can remove this digit with subtraction and division by 10 (or divide and floor). This makes for a pretty simple loop:
function digits(numbers){
if (numbers == 0) return [numbers]
let res = []
while (numbers){
let n = numbers % 10
res.push(n)
numbers = (numbers - n) / 10
}
return res.reverse()
}
console.log(digits(1279020))
This takes the numbers in reverse order so you either have to unshift the results on to the array or push and reverse at the end.
One of the nice things about this, is that you can find the digits of different bases by swapping out 10 for a the base of your choice:
function digits(numbers, base){
if (numbers == 0) return [numbers]
let res = []
while (numbers){
let n = numbers % base
res.push(n)
numbers = (numbers - n) / base
}
return res.reverse()
}
// binary
console.log(digits(20509, 2).join(''))
console.log((20509).toString(2))
// octal
console.log(digits(20509, 8).join(''))
console.log((20509).toString(8))
Although once your base is larger than 10 you will have to map those digits to the appropriate letters.
One approach would be to iterate through the number of digits and calculate the difference of each modulo by base, and then populate the output list from the result of each iteration.
A quick way to identify the number of digits in your base 10 input would be the following:
Math.floor(Math.log(input) / Math.LN10 + 1) // 5 for input of 12349
Next, iterate through this range and for each iteration, calculate the base of the current and previous iterations, and perform module of the input against these. The digit for the current iteration is then derived from the difference of the modulo calculations like this:
function arrayFromInput(input) {
const output = [];
for (let i = 0; i < Math.floor(Math.log(input) / Math.LN10 + 1); i++) {
const lastBase = Math.pow(10, i);
const nextBase = Math.pow(10, i + 1);
const lastMod = input % lastBase;
const nextMod = input % nextBase;
const digit = (nextMod - lastMod) / lastBase;
output.unshift(digit);
}
return output;
}
console.log(arrayFromInput(12345), '= [1,2,3,4,5]');
console.log(arrayFromInput(12), '= [1,2]');
console.log(arrayFromInput(120), '= [1,2 0]');
console.log(arrayFromInput(9), '= [9]');
console.log(arrayFromInput(100), '= [1,0,0]');

Sorting Arrays Javascript

I am brand new to javascript(I have been exposed to DOM manipulation, however for this assignment we can display input in a simple console.log according to the prof) and I have came across this problem that was due for a school assignment, I need to take user input of 3 numbers, display them, and show the max and min number entered, as well as the average.
The code I have below preforms as I intended but what I am looking for is feedback for improvements, I am still in the process of training my brain to break down these types of problems as well as organize my thinking. I would like to be practicing the "best" methods or most effective methods, as my thinking and logic is not yet defined and I am in the stage where everything is new so I may as learn the most effective ways/strategies. Any improvements or better ways to solve this question is greatly appreciated.
Thanks!
let num = parseFloat(prompt("enter your first number"));
let num1 = parseFloat(prompt("enter your second number"));
let num2 = parseFloat(prompt("enter your third number"));
let avg = parseFloat(console.log('The Average of The Numbers',
num, ',', num1, ',', num2, 'Is:', (num + num1 + num2) / 3));
let numTot = parseFloat(console.log(`The Numbers You Have Entered
Are`, num, +num1, +num2));
let total = parseFloat(console.log('The Total Of', num, '+', num1,
'+', num2, 'Is :', num + num1 + num2));
let highest = Math.max(num, num1, num2);
let lowest = Math.min(num, num1, num2);
console.log("The Highest Number Entered Is:", highest);
console.log("The Lowest Number Entered Is:", lowest);
Here's how I would do it:
Declare your numbers in an array. Prefix them with + to coerce them
from a String to Number.
Array.reduce to loop over your array and calculate the average.
Use spread syntax to obtain min/max values in the accumulator object,
you pass to .reduce.
// prompt returns a String, prefix with +
// to coerce them to Numbers, since we'll be
// working with numbers.
const numbers = [
+prompt('Enter number 1'),
+prompt('Enter number 2'),
+prompt('Enter number 3')
]
const result = numbers.reduce((acc, number, index) => {
// For each number:
// Add the number to the accumulator sum.
acc.sum += number
// If this is the last iteration:
if (index === numbers.length - 1) {
// Calculate the average from the sum.
acc.avg = acc.sum / numbers.length
// Also discard the sum property, we no longer need it.
delete acc.sum
}
// Return the accumulator for the next iteration.
return acc
}, {
// Our accumulator object, initialised with min/max values.
min: Math.min(...numbers),
max: Math.max(...numbers),
sum: 0,
avg: 0
})
// Log the processed accumulator.
console.log(result)
Why use a loop at all?
Array.reduce loops over an array, similarly to how a for loop does. Using a loop-like construct allows you to add more numbers in the numbers array without needing to modify your calculations code.
Why divide at the end of the loop?
Summing the numbers and dividing once at the end of the loop helps avoid numerical errors.
If you do acc.avg = acc.avg + number / numbers.length on each iteration you'll start noticing that the average turns out to be a bit off. Try it just for the sake of it.
Might look a bit complex for a beginner but those 2 concepts (esp. Array.reduce) are worth looking into. FWIW, the classroom example given for teaching Array.reduce is calculating
averages from an array of numbers.
If you want to use advances features, then reference to the Nik Kyriakides answer. On this approach I will use a for loop to ask for numbers in an iterative way and calculate the minimun, maximun and total progressively. The average could be obtained dividing total by the quantity of numbers you asked for:
const numbersToAsk = 3;
let max, min, avg, total = 0;
for (var i = 1; i <= numbersToAsk; i++)
{
// Ask the user for a new number and get it.
let num = parseFloat(prompt("enter your number " + i));
// Sum the new number to the previous accumulated total.
total += num;
// Recalculate the new maximum, if there wasn't a previous one,
// just assign the current number.
max = !max ? num : Math.max(max, num);
// Recalculate the new minimum, if there wasn't a previous one,
// just assign the current number.
min = !min ? num : Math.min(min, num);
}
// Calulate the average.
avg = total / numbersToAsk;
// Show the obtained results on the console.
console.log(
"Total: " + total,
"Average: " + avg,
"Min: " + min,
"Max: " + max
);

How to split a number into its digits in Javascript?

I want to Split a number into its digit (for example 4563 to 4 , 5 , 6 , 3 ) then addiction this digits. (for example: 4+5+6+3=18)
I can write code for 3 digit or 2 digit and ... numbers seperately but I cant write a global code for each number.
so this is my code for 2 digit numbers:
var a = 23
var b = Math.floor(a/10); // 2
var c = a-b*10; // 3
var total = b+c; // 2+3
console.log(total); // 5
and this is my code for 3 digit numbers:
var a = 456
var b = Math.floor(a/100); // 4
var c = a-b*100; // 56
var d = Math.floor(c/10); // 5
var e = c-d*10; // 6
var total = b+d+e; // 4+5+6
console.log(total); // 15
but I cant write a code to work with each number.How can I write a global code for each number?
In modern browsers you can do an array operation like
var num = 4563;
var sum = ('' + num).split('').reduce(function (sum, val) {
return sum + +val
}, 0)
Demo: Fiddle
where you first create an array digits then use reduce to sum up the values in the array
var num = 4563;
var sum = 0;
while(num > 0) {
sum += num % 10;
num = Math.floor(num / 10);
}
console.log(sum);
Do number%10(modulus) and then number/10(divide) till the number is not 0
I hope the following example is useful to you:
var text="12345";
var total=0;
for (i=0;i<text.length;i++)
{
total+= parseInt(text[i]);
}
alert(total);
This solution converts the number to string, splits it into characters and process them in the callback function (prev is the result from the previous call, current is the current element):
var a = 456;
var sum = a.toString().split("").reduce(function(prev, current){
return parseInt(prev) + parseInt(current)
})
Here is how I would approach the problem. The trick I used was to split on the empty string to convert the string to an array and then use reduce on the array.
function digitSum(n) {
// changes the number to a string and splits it into an array
return n.toString().split('').reduce(function(result, b){
return result + parseInt(b);
}, 0);
}
As mentioned by several other posters (hat tip to my commenter), there are several other good answers to this question as well.
Here is my solution using ES6 arrow functions as call back.
- Convert the number into a string.
- Split the string into an array.
- Call the map method on that array.
- Callback function parse each digit to an array.
let number = 65535;
//USING MAP TO RETURN AN ARRAY TO DIGITS
let digits = number.toString()
.split("")
.map(num => parseInt(num));
//OUTPUT TO DOM
digits.forEach(
digit =>
document.querySelector("#out").innerHTML += digit + "<br>"
);
<p id="out"></p>
1) You can cast input number to string, using .toString() method and expand it into array with spread (...) operator
const splitNumber = n => [ ...n.toString() ]
2) Another short way - using recursion-based solution like:
const splitNumber = n => n ? [ ...splitNumber(n/10|0), n%10 ] : []

How to compute the sum and average of elements in an array? [duplicate]

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
This question already has answers here:
How to find the sum of an array of numbers
(59 answers)
Closed 3 months ago.
I am having problems adding all the elements of an array as well as averaging them out. How would I do this and implement it with the code I currently have? The elements are supposed to be defined as I have it below.
<script type="text/javascript">
//<![CDATA[
var i;
var elmt = new Array();
elmt[0] = "0";
elmt[1] = "1";
elmt[2] = "2";
elmt[3] = "3";
elmt[4] = "4";
elmt[5] = "7";
elmt[6] = "8";
elmt[7] = "9";
elmt[8] = "10";
elmt[9] = "11";
// Problem here
for (i = 9; i < 10; i++){
document.write("The sum of all the elements is: " + /* Problem here */ + " The average of all the elements is: " + /* Problem here */ + "<br/>");
}
//]]>
</script>
A solution I consider more elegant:
const sum = times.reduce((a, b) => a + b, 0);
const avg = (sum / times.length) || 0;
console.log(`The sum is: ${sum}. The average is: ${avg}.`);
ES6
const average = arr => arr.reduce( ( p, c ) => p + c, 0 ) / arr.length;
const result = average( [ 4, 4, 5, 6, 6 ] ); // 5
console.log(result);
var sum = 0;
for( var i = 0; i < elmt.length; i++ ){
sum += parseInt( elmt[i], 10 ); //don't forget to add the base
}
var avg = sum/elmt.length;
document.write( "The sum of all the elements is: " + sum + " The average is: " + avg );
Just iterate through the array, since your values are strings, they have to be converted to an integer first. And average is just the sum of values divided by the number of values.
Calculating average (mean) using reduce and ES6:
const average = list => list.reduce((prev, curr) => prev + curr) / list.length;
const list = [0, 10, 20, 30]
average(list) // 15
Shortest one liner for Average
const avg = arr => arr.reduce((acc,v,i,a)=>(acc+v/a.length),0);
Shortest one liner for Sum
const sum = arr => arr.reduce((a,b)=>a+b);
Let's imagine we have an array of integers like this:
var values = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
The average is obtained with the following formula
A= (1/n)Σxi ( with i = 1 to n ) ... So: x1/n + x2/n + ... + xn/n
We divide the current value by the number of values and add the previous result to the returned value.
The reduce method signature is
reduce(callback[,default_previous_value])
The reduce callback function takes the following parameters:
p : Result
of the previous calculation
c : Current value (from the current index)
i : Current array element's index value
a : The current reduced Array
The second reduce's parameter is the default value ... (Used in case the array is empty ).
So the average reduce method will be:
var avg = values.reduce(function(p,c,i,a){return p + (c/a.length)},0);
If you prefer you can create a separate function
function average(p,c,i,a){return p + (c/a.length)};
function sum(p,c){return p + c)};
And then simply refer to the callback method signature
var avg = values.reduce(average,0);
var sum= values.reduce(sum,0);
Or Augment the Array prototype directly..
Array.prototype.sum = Array.prototype.sum || function (){
return this.reduce(function(p,c){return p+c},0);
};
It's possible to divide the value each time the reduce method is called..
Array.prototype.avg = Array.prototype.avg || function () {
return this.reduce(function(p,c,i,a){return p+(c/a.length)},0);
};
Or even better , using the previously defined Array.protoype.sum()
method, optimize the process my calling the division only once :)
Array.prototype.avg = Array.prototype.avg || function () {
return this.sum()/this.length;
};
Then on any Array object of the scope:
[2, 6].avg();// -> 4
[2, 6].sum();// -> 8
NB: an empty array with return a NaN wish is more correct than 0 in my point of view and can be useful in specific use cases.
generally average using one-liner reduce is like this
elements.reduce(function(sum, a,i,ar) { sum += a; return i==ar.length-1?(ar.length==0?0:sum/ar.length):sum},0);
specifically to question asked
elements.reduce(function(sum, a,i,ar) { sum += parseFloat(a); return i==ar.length-1?(ar.length==0?0:sum/ar.length):sum},0);
an efficient version is like
elements.reduce(function(sum, a) { return sum + a },0)/(elements.length||1);
Understand Javascript Array Reduce in 1 Minute
http://www.airpair.com/javascript/javascript-array-reduce
as gotofritz pointed out seems Array.reduce skips undefined values.
so here is a fix:
(function average(arr){var finalstate=arr.reduce(function(state,a) { state.sum+=a;state.count+=1; return state },{sum:0,count:0}); return finalstate.sum/finalstate.count})([2,,,6])
You can also use lodash, _.sum(array) and _.mean(array) in Math part (also have other convenient stuff).
_.sum([4, 2, 8, 6]);
// => 20
_.mean([4, 2, 8, 6]);
// => 5
Not the fastest, but the shortest and in one line is using map() & reduce():
var average = [7,14,21].map(function(x,i,arr){return x/arr.length}).reduce(function(a,b){return a + b})
I use these methods in my personal library:
Array.prototype.sum = Array.prototype.sum || function() {
return this.reduce(function(sum, a) { return sum + Number(a) }, 0);
}
Array.prototype.average = Array.prototype.average || function() {
return this.sum() / (this.length || 1);
}
EDIT:
To use them, simply ask the array for its sum or average, like:
[1,2,3].sum() // = 6
[1,2,3].average() // = 2
In ES6-ready browsers this polyfill may be helpful.
Math.sum = (...a) => Array.prototype.reduce.call(a,(a,b) => a+b)
Math.avg = (...a) => Math.sum(...a)/a.length;
You can share same call method between Math.sum,Math.avg and Math.max,such as
var maxOne = Math.max(1,2,3,4) // 4;
you can use Math.sum as
var sumNum = Math.sum(1,2,3,4) // 10
or if you have an array to sum up,you can use
var sumNum = Math.sum.apply(null,[1,2,3,4]) // 10
just like
var maxOne = Math.max.apply(null,[1,2,3,4]) // 4
One sneaky way you could do it although it does require the use of (the much hated) eval().
var sum = eval(elmt.join('+')), avg = sum / elmt.length;
document.write("The sum of all the elements is: " + sum + " The average of all the elements is: " + avg + "<br/>");
Just thought I'd post this as one of those 'outside the box' options. You never know, the slyness might grant you (or taketh away) a point.
Here is a quick addition to the “Math” object in javascript to add a “average” command to it!!
Math.average = function(input) {
this.output = 0;
for (this.i = 0; this.i < input.length; this.i++) {
this.output+=Number(input[this.i]);
}
return this.output/input.length;
}
Then i have this addition to the “Math” object for getting the sum!
Math.sum = function(input) {
this.output = 0;
for (this.i = 0; this.i < input.length; this.i++) {
this.output+=Number(input[this.i]);
}
return this.output;
}
So then all you do is
alert(Math.sum([5,5,5])); //alerts “15”
alert(Math.average([10,0,5])); //alerts “5”
And where i put the placeholder array just pass in your variable (The input if they are numbers can be a string because of it parsing to a number!)
I found Mansilla's answer to work fine with the extension of making sure that I am doing summation of floats and not concatonation of strings using parseFloat():
let sum = ourarray.reduce((a, b) => parseFloat(a) + parseFloat(b), 0);
let avg = (sum / ourarray.length) || 0;
console.log(sum); // print out sum
console.log(avg); // print out avg
set your for loop counter to 0.... you're getting element 9 and then you're done as you have it now. The other answers are basic math. Use a variable to store your sum (need to cast the strings to ints), and divide by your array length.
Start by defining all of the variables we plan on using. You'll note that for the numbers array, I'm using the literal notation of [] as opposed to the constructor method array(). Additionally, I'm using a shorter method to set multiple variables to 0.
var numbers = [], count = sum = avg = 0;
Next I'm populating my empty numbers array with the values 0 through 11. This is to get me to your original starting point. Note how I'm pushing onto the array count++. This pushing the current value of count, and then increments it for the next time around.
while ( count < 12 )
numbers.push( count++ );
Lastly, I'm performing a function "for each" of the numbers in the numbers array. This function will handle one number at a time, which I'm identifying as "n" within the function body.
numbers.forEach(function(n){
sum += n;
avg = sum / numbers.length;
});
In the end, we can output both the sum value, and the avg value to our console in order to see the result:
// Sum: 66, Avg: 5.5
console.log( 'Sum: ' + sum + ', Avg: ' + avg );
See it in action online at http://jsbin.com/unukoj/3/edit
I am just building on Abdennour TOUMI's answer. here are the reasons why:
1.) I agree with Brad, I do not think it is a good idea to extend object that we did not create.
2.) array.length is exactly reliable in javascript, I prefer Array.reduce beacuse a=[1,3];a[1000]=5; , now a.length would return 1001.
function getAverage(arry){
// check if array
if(!(Object.prototype.toString.call(arry) === '[object Array]')){
return 0;
}
var sum = 0, count = 0;
sum = arry.reduce(function(previousValue, currentValue, index, array) {
if(isFinite(currentValue)){
count++;
return previousValue+ parseFloat(currentValue);
}
return previousValue;
}, sum);
return count ? sum / count : 0;
};
Array.prototype.avg=function(fn){
fn =fn || function(e,i){return e};
return (this.map(fn).reduce(function(a,b){return parseFloat(a)+parseFloat(b)},0) / this.length ) ;
};
Then :
[ 1 , 2 , 3].avg() ; //-> OUT : 2
[{age:25},{age:26},{age:27}].avg(function(e){return e.age}); // OUT : 26
On evergreen browsers you can use arrow functions
avg = [1,2,3].reduce((a,b) => (a+b);
Running it 100,000 times, the time difference between the for loop approach and reduce is negligible.
s=Date.now();for(i=0;i<100000;i++){ n=[1,2,3]; a=n.reduce((a,b) => (a+b)) / n.length };
console.log("100k reduce took " + (Date.now()-s) + "ms.");
s=Date.now();for(i=0;i<100000;i++){n=[1,2,3]; nl=n.length; a=0; for(j=nl-1;j>0;j--){a=a+n[j];} a/nl };
console.log("100k for loop took " + (Date.now()-s) + "ms.");
s=Date.now();for(i=0;i<1000000;i++){n=[1,2,3]; nl=n.length; a=0; for(j=nl-1;j>0;j--){a=a+n[j];} a/nl };
console.log("1M for loop took " + (Date.now()-s) + "ms.");
s=Date.now();for(i=0;i<1000000;i++){ n=[1,2,3]; a=n.reduce((a,b) => (a+b)) / n.length };
console.log("1M reduce took " + (Date.now()-s) + "ms.");
/*
* RESULT on Chrome 51
* 100k reduce took 26ms.
* 100k for loop took 35ms.
* 10M for loop took 126ms.
* 10M reduce took 209ms.
*/
If you are in need of the average and can skip the requirement of calculating the sum, you can compute the average with a single call of reduce:
// Assumes an array with only values that can be parsed to a Float
var reducer = function(cumulativeAverage, currentValue, currentIndex) {
// 1. multiply average by currentIndex to find cumulative sum of previous elements
// 2. add currentValue to get cumulative sum, including current element
// 3. divide by total number of elements, including current element (zero-based index + 1)
return (cumulativeAverage * currentIndex + parseFloat(currentValue))/(currentIndex + 1)
}
console.log([1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce(reducer, 0)); // => 5.5
console.log([].reduce(reducer, 0)); // => 0
console.log([0].reduce(reducer, 0)); // => 0
console.log([].reduce(reducer, 0)); // => 0
console.log([,,,].reduce(reducer, 0)); // => 0
console.log([].reduce(reducer, 0)); // => 0
If anyone ever needs it - Here is a recursive average.
In the context of the original question, you may want to use the recursive average if you allowed the user to insert additional values and, without incurring the cost of visiting each element again, wanted to "update" the existing average.
/**
* Computes the recursive average of an indefinite set
* #param {Iterable<number>} set iterable sequence to average
* #param {number} initAvg initial average value
* #param {number} initCount initial average count
*/
function average(set, initAvg, initCount) {
if (!set || !set[Symbol.iterator])
throw Error("must pass an iterable sequence");
let avg = initAvg || 0;
let avgCnt = initCount || 0;
for (let x of set) {
avgCnt += 1;
avg = avg * ((avgCnt - 1) / avgCnt) + x / avgCnt;
}
return avg; // or {avg: avg, count: avgCnt};
}
average([2, 4, 6]); //returns 4
average([4, 6], 2, 1); //returns 4
average([6], 3, 2); //returns 4
average({
*[Symbol.iterator]() {
yield 2; yield 4; yield 6;
}
}); //returns 4
How:
this works by maintaining the current average and element count. When a new value is to be included you increment count by 1, scale the existing average by (count-1) / count, and add newValue / count to the average.
Benefits:
you don't sum all the elements, which may result in large number that cannot be stored in a 64-bit float.
you can "update" an existing average if additional values become available.
you can perform a rolling average without knowing the sequence length.
Downsides:
incurs lots more divisions
not infinite - limited to Number.MAX_SAFE_INTEGER items unless you employ BigNumber
Having read the other choices, I will try to make a simpler version for the future viewers, elaborating on the existing code and not creating a more elegant one. First of all, you declared the numbers as strings. Apart from the .parseInt we can also do:
const numberConverter = elmt.map(Number);
So what map does is that it "returns a copy of the original array". But I convert its values to numbers. Then we can use the reduce method (It can also be simpler, but I am writing easy to read versions and I also have 2 average methods) What the reduce method does is it has an accumulator that gets bigger and bigger if you add values to it, as it iterates through the array and adds (in this case) the currentValue to it.:
var i;
const elmt = new Array();
elmt[0] = '0';
elmt[1] = '1';
elmt[2] = '2';
elmt[3] = '3';
elmt[4] = '4';
elmt[5] = '7';
elmt[6] = '8';
elmt[7] = '9';
elmt[8] = '10';
elmt[9] = '11';
console.log(elmt);
const numberConverter = elmt.map(Number);
const sum = numberConverter.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0);
const average = numberConverter.reduce(
(accumulator, currentvalue, index, numArray) => {
return accumulator + currentvalue / numArray.length;
},
0
);
const average2 =
numberConverter.reduce(
(accumulator, currentValue) => accumulator + currentValue,
0
) / numberConverter.length;
for (i = 9; i < 10; i++) {
console.log(
`The sum of all the elements is: ${sum}. <br> The average of all the elements is: ${average2}`
);}
Unless I missed something, every solution up to this point uses the length of the list to calculate the average after summing the values.
There is a downside to this approach that a slightly modified, yet still simple algorithm will address without the downsides.
The downside is that you assuming that there won't be an overflow by summing all the numbers. If you have a lot of numbers that are very big, and you add them all up, they may exceed the maximum size that can fit into the data type.
A better approach is to simply calculate the average as you go, rather than summing it and then dividing with the length at the end:
function getAvg(values) {
return values.reduce((m, x, i) => m + (x - m) / (i + 1), 0)
}
Props to Knuth's "Art of Computer Programming" vol. 2.
just for fun
let avg = [81, 77, -88, 195, 6.8].reduce((a,e,i) => (a*i+e)/(i+1));
console.log(avg)
Just for kicks:
var elmt = [0, 1, 2,3, 4, 7, 8, 9, 10, 11], l = elmt.length, i = -1, sum = 0;
for (; ++i < l; sum += elmt[i])
;
document.body.appendChild(document.createTextNode('The sum of all the elements is: ' + sum + ' The average of all the elements is: ' + (sum / l)));
I think we can do like
var k=elmt.reduce(function(a,b){return parseFloat(a+parseFloat(b));})
var avg=k/elmt.length;
console.log(avg);
I am using parseFloat twice because
when
1) you add (a)9+b("1") number then result will be "91" but we want addition. so i used parseFloat
2)When addition of (a)9+parseFloat("1") happen though result will be "10" but it will be in string which we don't want so again i used parseFloat.
I hope i am clear. Suggestions are welcome
Here is my rookie way of simply finding the avg. Hope this helps somebody.
function numAvg(num){
var total = 0;
for(var i = 0;i < num.length; i++) {
total+=num[i];
}
return total/num.length;
}
here's your one liner:
var average = arr.reduce((sum,item,index,arr)=>index !== arr.length-1?sum+item:sum+item/arr.length,0)
I think this may be a direct solution to calculate the average with a for loop and function.
var elmts = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
function average(arr) {
var total = 0;
for (var i = 0; i < arr.length; i++) {
total += arr[i];
}
console.log(Math.round(total/arr.length));
}
average(elmts);
There seem to be an endless number of solutions for this but I found this to be concise and elegant.
const numbers = [1,2,3,4];
const count = numbers.length;
const reducer = (adder, value) => (adder + value);
const average = numbers.map(x => x/count).reduce(reducer);
console.log(average); // 2.5
Or more consisely:
const numbers = [1,2,3,4];
const average = numbers.map(x => x/numbers.length).reduce((adder, value) => (adder + value));
console.log(average); // 2.5
Depending on your browser you may need to do explicit function calls because arrow functions are not supported:
const r = function (adder, value) {
return adder + value;
};
const m = function (x) {
return x/count;
};
const average = numbers.map(m).reduce(r);
console.log(average); // 2.5
Or:
const average1 = numbers
.map(function (x) {
return x/count;
})
.reduce(function (adder, value) {
return adder + value;
});
console.log(average1);

Categories