How do I write loops inside functions? - javascript

The question is to write a for loop inside a function that will take in array and return the total of all the numbers added together. Not sure what I'm doing wrong here.
let total = 0
function totalGoals(numbers) {
for (let i = 0; i<numbers.length; i++) {
let num = numbers[i]
total = total + num
}
return total
}
totalGoals([0, 1, 2])

First, lets confirm that you HAVE to learn the basics of Javascript and basic looping (using for loop for example), but also on your journey, you have to learn what tools in the language might make your life easier and your code mode readable.
When it comes to accumulative operation (like adding and so..) you should learn about "reduce" method, which you can write your desired function like:
function totalGoals(numbers){
return numbers.reduce((acc, val) => acc + val, 0)
}

You define total variable globally (outside of function), so here are 2 options: it's better to define variable for sum inside the function:
function totalGoals(numbers) {
let total = 0
for (let i = 0; i<numbers.length; i++) {
let num = numbers[i]
total = total + num
}
return total
}
totalGoals([0, 1, 2])
or if it is necessary to be global - set it to 0 in the start of function, so if won't be affected if function is called more than once:
let total = 0
function totalGoals(numbers) {
total = 0
for (let i = 0; i<numbers.length; i++) {
let num = numbers[i]
total = total + num
}
return total
}
totalGoals([0, 1, 2])

You have some sytanxys problems. Try this code:
function totalGoals(numbers) {
let total= 0, num = 0;
for (let i = 0; i< numbers.length; i++) {
num = numbers[i];
total = total + num;
}
alert(total);
return total;
}
totalGoals([0, 1, 2]);
You need to learn about Scope of variable:
https://www.w3schools.com/js/js_scope.asp
And you need be more carefully with your sintaxys:
Dont forget add ; at final of a code line.
And also you are start the variable num more than one time with the word let inside your loop.

Related

Finding the sum of a "counter" variable loop that ran ten times then was pushed into the "numbers" array. Each way I tried resulted with a list

I'm asking for help to find the sum of an array with elements that were pushed from a counter variable that had previously looped 10 times. I'm new to Javascript and was practicing for an assessment, and I've tried several different ways to do it and have only resulted with just a list of the elements within the numbers array.
var counter = 10;
var numbers = [];
for (i = 1; i <= 10; i ++) {
counter = [i + 73];
numbers.push(counter);
}
console.log(numbers);
function sum(arr) {
var s = 0;
for(var i = 0; i < arr.length; i++) {
s = s += arr[i];
}
return s;
}
console.log(sum([numbers]));
function getArraySum(a) {
var total = 0;
for (var i in a) {
total += a[i];
}
return total;
}
var numbers = getArraySum([numbers]);
console.log(numbers);
you should push only the value of counter without the brackets and then make a reduce to have the sum of each number in the array
var counter = 10;
var numbers = [];
for (i = 1; i <= 10; i++) {
counter = i + 73;
numbers.push(counter);
}
console.log(numbers.reduce((a,b) => a+b));
You had a couple of typos in the code:
Typos
You were wrapping the sum in square brackets:
counter = [i + 73];
You should just remove the brackets like:
counter = i + 73;
2. You were wrapping a value that is already an array in square brackets while passing it as an argument to a function:
sum( [numbers] )
// ...
getArraySum( [numbers] );
You should remove the brackets, like this:
sum( numbers );
// ...
getArraySum( numbers );
Fix
I updated the code that you shared to fix the above-mentioned things:
var numbers = [];
// Loop 10 times and push each number to the numbers array
for (var i = 1; i <= 10; i ++) {
var sumNumbers = i + 73;
numbers.push(sumNumbers);
}
console.log(numbers);
function sum(arr) {
var total = 0;
for(var i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
// Call the function by passing it the variable numbers, holding an array
var result1 = sum(numbers);
console.log( result1 );
function getArraySum(a) {
var total = 0;
for (var i in a) {
total += a[i];
}
return total;
}
var result2 = getArraySum(numbers);
console.log(result2);

why my code doesn't work when I am trying to concatenate a function's return value with a string?

So, in this code I have a string of 0's and 1's and the length of the string is 32, which will be split in 6 equal parts but the last part will have the length of 2 so I will add (4) 0's after that which will make its length 6. So I wrote a function that will add the remaining 0's which is padding(num).
And that function will be invoked in side the slicing(str) function.
But the code breaks when I try to do execute.
Any help?
Thanks.
// This code works.
function padding0s(num) {
let s = "";
for (i = 0; i < 6 - num; i++) {
s += "0";
}
return s;
}
function slicing(str) {
let k = 6;
let res = [];
let temp1 = 0;
let f = padding0s(2);
for (i = 0; i < str.length; ) {
res.push(str.slice(i, k));
i += 6;
k += 6;
if (res[temp1].length !== 6) {
res[temp1] += f;
}
temp1++;
}
console.log(res);
}
slicing("01000011010011110100010001000101");
// But this does not..
function padding0s(num) {
let s = "";
for (i = 0; i < 6 - num; i++) {
s += "0";
}
return s;
}
function slicing(str) {
let k = 6;
let res = [];
let temp1 = 0;
for (i = 0; i < str.length; ) {
res.push(str.slice(i, k));
i += 6;
k += 6;
if (res[temp1].length !== 6) {
let f = padding0s(res[temp1].length);
res[temp1] += f;
}
temp1++;
}
console.log(res);
}
slicing("01000011010011110100010001000101");
Always define variables before using them
Not doing so can result in undefined behaviour, which is exactly what is happening in your second case. Here is how:
for (i = 0; i < str.length; ) {...}
// ^ Assignment to undefined variable i
In the above for-loop, by using i before you define it, you are declaring it as a global variable. But so far, so good, as it doesn't matter, if not for this second problem. The real problem is the call to padding0s() in your loop. Let's look at padding0s:
function padding0s(num) {
...
for (i = 0; i < 6 - num; i++) {
s += "0";
}
}
This is another loop using i without defining it. But since i was already defined as a global variable in the parent loop, this loop will be setting its value. So in short, the value of i is always equal to 6 - num in the parent loop. Since your exit condition is i < str.length, with a string of length 32 the loop will run forever.
You can get around this in many ways, one of which you've already posted. The other way would be to use let i or var i instead of i in the parent loop. Even better is to write something like this (but beware that padEnd may not work on old browsers):
function slicing(str) {
return str.match(/.{1,6}/g).map((item) => {
return item.padEnd(6, "0");
});
}
console.log(slicing("01000011010011110100010001000101"));

Avoid multiple loops in JS implementation of Bonferroni inequality

I was trying to implement the "Bonferroni inequality" which models the probability of the union of many independent events for a data science use case on GCP BigQuery using a Javascript UDF. However I'm quite unfamiliar with JS and have no clue of the good practices.
The formula to apply is the following:
P(U Ai) = SUM(P(Ai)) - SUM(P(Ai)*P(Aj)) + SUM(P(Ai)*P(Aj)*P(Ak) - ... i != j != k
My input for this function is an array of the single event probabilities:
[P(A1), P(A2), P(A3), ...]
I instinctively made "for loops" in rows to get the result however, it hurts to see a code this ugly so was wondering if any of you had an idea on how to achieve it in a more elegant and optimized way?
Here is the function I wrote for a level 4 Bonferroni inequality :
function unionBoundProbability(probList){
var intersection2 = 0;
var intersection3 = 0;
var intersection4 = 0;
var i = 0;
var j = 0;
var k = 0;
var l = 0;
var sum = 0;
var product = 1;
var sum = probList.reduce((a, b) => a + b, 0);
for(i = 0; i < probList.length; i++){
product *= probList[i];
for(j = i+1; j < probList.length; j++){
intersection2 += probList[i]*probList[j];
for(k = j+1; k < probList.length; k++){
intersection3 += probList[i]*probList[j]*probList[k];
for(l = k+1; l < probList.length; l++){
intersection4 += probList[i]*probList[j]*probList[k]*probList[l];
}
}
}
}
switch (probList.length) {
case 0:
return 0;
break;
case 1:
return probList[0];
break;
case 2:
return sum - product;
break;
case 3:
return sum - intersection2 + product;
break
case 4:
return sum - intersection2 + intersection3 - product;
case 5 :
return sum - intersection2 + intersection3 - intersection4 + product;
default:
return Math.max((sum - intersection2 + intersection3 - intersection4), Math.max.apply(Math, probList));
}
}
What I am trying to do is to calculate an approximation of the probability of the union of all the probabilities passed as the input.
If I have less than 5 probabilities, then the switch statement applies the exact formula. Otherwise, the default case applies the Bonferroni approximation, (As I'm modeling the chance of a signal to be received, if the estimation is less than the probability with the best antenna then I keep the best antenna).
Thank you for your help
This example follows the below equation from https://www.probabilitycourse.com/chapter6/6_2_1_union_bound_and_exten.php
P(⋃(i=1 => n)Ai)=∑(i=1 => n) P(Ai) − ∑(i<j) P(Ai ∩ Aj) + ∑(i<j<k) P(Ai ∩ Aj ∩ Ak) − ... +(−1)^n−1 P(⋂(i=1 => n) Ai)
I don't know the reason why you included factorials in the example you gave, but I didn't include factorials as they are not there in the above equation.
// Recursive function to update sums of each level
function updateSums(sums, probList, maxLevel, currentLevel = 1, currentProduct = 1, lastIndex = -1) {
// Example case: maxLevel = 4, curentLevel = 3, path = { 1: 0, 2: 1 }, currentProduct = probList[0] * probList[1]
// Loops through all entries except 0 and 1 and adds the products to sums[2], for each entry also calculates level 4 sums
for (let i = lastIndex + 1; i < probList.length; i++) {
const nextProduct = currentProduct * probList[i];
sums[currentLevel - 1] += nextProduct;
if (currentLevel < maxLevel) {
// get the next level product sums for current product
updateSums(sums, probList, maxLevel, currentLevel + 1, nextProduct, i);
}
}
}
// Main function
function inequality(probList) {
probList = probList.sort((a, b) => b - a).slice(0, 4);
// Calculate maxLevel
const maxLevel = probList.length;
if (!maxLevel) return 0;
// create am array of sums, each entry represents 1 level
const sums = (new Array(maxLevel)).fill(0);
updateSums(sums, probList, maxLevel);
return sums.reduce((a, c, i) => {
return a + ((i % 2) ? -1 : 1) * c;
}, 0);
}
console.log(inequality(probList));
PS: This is written in ES6
We may avoid a recurrence
Say A of size n
According to your formula we may consider
we take 1 element from A: C_n^1
we take 2 elements from A: C_n^2
we take 3 elements from A: C_n^3
Instead of recomputing every k-utuple (unordered tuple), we can simply keep the (k-1)-utuples of the previous layer
e.g let's take array [1,2,3,4,5]
first layer: 1,2,3,4,5
second layer: 1-2, 1-3, 1-4, 1-5, 2-3, 2-4, ..., 4-5
third layer: 1-2-{i}(i for 3 to 5), 1-3-{i}, ...
And for our case: we don't really need the whole utuple: just its last idx, and its value (product of its elems)
algo be like
function bonferroni(A, nlev){
let lv = 0;
let tot = 0;
//i refers to the index of the last element added to the tuple
//s refers to its value
//here we initialize with i=-1 just so the first while loop builds an equivalent of "A"
let layer = [{i:-1, s:1}];
while(lv < nlev){
let sum = 0;
let next = [];
layer.forEach(utuple=>{
for(let i = utuple.i+1; i<A.length; ++i){
let s = utuple.s * A[i];
sum += s;
next.push({i, s});
}
})
layer = next;
if((lv % 2)==0){
tot += sum;
}else{
tot -= sum;
}
lv++;
}
return tot;
}
The verbose version being:
function bonferroniVerbose(A, nlev){
let lv = 0;
let tot = 0;
//i refers to the index of the last element added to the tuple
//s refers to its value
//here we initialize with i=-1 just so the first while loop builds an equivalent of "A"
let layer = [{t:[], i:-1, s:1}];
while(lv < nlev){
console.log('--------------layer', lv);
let sum = 0;
let next = [];
layer.forEach(utuple=>{
for(let i = utuple.i+1; i<A.length; ++i){
let s = utuple.s * A[i];
sum += s;
let t = utuple.t.concat(A[i]);
next.push({t, i, s});
console.log('summing', t.join('*'), '->', s);
}
})
layer = next;
if((lv % 2)==0){
tot += sum;
}else{
tot -= sum;
}
lv++;
}
return tot;
}
console.log(bonferroniVerbose([1,2,3,4,5], 3))

Average of array by using a callback function in Javascript

I'm having a problem to sum and find the average of an array. I keep getting average is 0.
I cant really see what the problem could be :
var a = [10,20,30,40]
var sum = 0
var avg = 0
function sumUP(a) {
for (var i=0; i<a.length; i++){
sum += a[i];
avg = (sum/a.length);
}
}
function display(avg, callback) {
document.write("Average of array is " + avg)
callback(average);
}
display(avg, sumUP);
thanks a lot in advance!
Instead of assigning to global variables, you should have sumUP return the calculated average so it can be used in your document.write. That's one of the purposes of functions - to encapsulate functionality and return values that can be used by other functions without unnecessary side-effects. You also need to calculate the average before you display it. (you were displaying it before you were calculating it, which of course leaves it displaying 0)
You should also take care not to use single-letter variable names, which are very hard to make sense of (not only for others reading your code, but also for you, when you come back to it later).
const array = [10, 20, 30, 40];
function sumUP(arr) {
let sum = 0;
for (var i = 0; i < arr.length; i++) {
sum += arr[i];
}
const avg = (sum / arr.length);
return avg;
}
function display(arr, callback) {
const avg = callback(arr);
document.write("Average of array is " + avg)
}
display(array, sumUP);
You should write code like this.
function sumUP(a) {
for (var i=0; i<a.length; i++){
sum += a[i];
}
avg = (sum/a.length);
}
take a look at : .reduce()
const arr = [10, 20, 30, 40]
const sum = arr.reduce((a,b) => a + b , 0)
const avg = sum / arr.length
function display(avg) {
document.write("Average of array is " + avg)
}
display(avg);
You do not need to pass avg to the callback and display function at all:
var a = [10,20,30,40];
var sum = 0;
var avg = 0;
function sumUP() {
for (var i=0; i<a.length; i++){
sum += a[i];
res = (sum/a.length);
}
}
function display(callback) {
callback();
document.write("Average of array is: " + res);
}
display(sumUP);
Here is the fix for your code.
var a = [10,20,30,40]
var sum = 0
var avg = 0
function sumUP(a) {
for (var i=0; i<a.length; i++){
sum += a[i];
}
avg = (sum/a.length);
}
function display(callback) {
callback(a);
document.write("Average of array is " + avg);
}
display(sumUP);
The first problem in your code was you are calling the callback function after the document write. It should be called first before the writing the result because these method have your logic.
And the avg that you are calling is not the global variable that you declare but the variable that is being used by the function. I remove it in your parameter because it was already declared as global and no need to pass in the display function.
I also exlude avg = (sum/a.length); in the for loop because it can be computed once, and that is when the for loop is done or when you get the total sum of your numbers.

JavaScript neglecting the else statement

I created a function which takes in two values..
Both are numbers represented by n & p. What the function does is that it gets the number n and splits it up then squares it to the value of p and sums them in an increasing order like this: n^p + n^(p+1) + n^(p+2) + ...
Here is the function
function digPow(n, p) {
// ...
let num = n.toString();
let pow = p;
let arrn = [];
let arrp = [];
for (let i = 0; i < num.length; i++) {
arrn.push(JSON.parse(num[i]));
}
let index = arrn.join('');
let sindex = index.split('');
for (let j = 0; j < sindex.length; j++) {
let power = p + j;
let indexs = sindex[j];
let Mathpow = Math.pow(indexs, power);
arrp.push(Mathpow);
}
let total = 0;
for (let m in arrp) {
total += arrp[m]
}
let secondVal = total / n;
let totals = total / secondVal;
let mx = [-1]
if (totals.length == n.length) {
return secondVal
} else {
return -1
}
}
Now i created variables and arrays to store up the values and then the if part is my problem.. The if/else statement is meant to let the program check if a particular variable totals is equal to n which is the input.. if true it should return a variable secondVal and if not it should return -1..
So far its only returning secondVal and i'snt returning -1 in cases where it should like:
digPow(92, 1) instead it returns 0.14130434782608695
What do i do?
totals and n are both numbers. They don't have a .length property, so both totals.length and n.length evaluate to undefined. Thus, they are equal to each other.
There are plenty of other weird things going on in your code, too. I'd recommend finding a good JavaScript tutorial and working through it to get a better feel for how the language (and programming in general) works.
Let's start by stripping out the redundant variables and circular-logic code from your function:
function digPow(n, p) {
let num = n.toString();
// let pow = p; // this is never used again
// let arrn = []; // not needed, see below
// let arrp = []; // was only used to contain values that are later summed; can instead just sum them in the first place
// this does the same thing as num.split(''), and isn't needed anyway:
//for (let i = 0; i < num.length; i++) {
// arrn.push(JSON.parse(num[i]));
//}
// this is the same as the original 'num' variable
// let index = arrn.join('');
// This could have been num.split(), but isn't needed anyway
// let sindex = index.split('');
let total = 0; // moved this line here from after the loop below:
for (let j = 0; j < num.length; j++) { // use num.length instead of the redundant sindex
let power = p + j;
// The only reason for the sindex array was to get individual characters from the string, which we can do with .charAt().
//let indexs = sindex[j];
let indexs = num.charAt(j);
let Mathpow = Math.pow(indexs, power);
//arrp.push(Mathpow); // No need to collect these in an array
total += Mathpow; // do this instead
}
// No need for this loop, since we can sum the total during the previous loop
// let total = 0;
//for (let m in arrp) {
// total += arrp[m]
//}
let secondVal = total / n;
// let totals = total / secondVal;
// The above is the same thing as total / total / n, which is:
let totals = 1/n;
// This is never used
//let mx = [-1]
// This was totals.length and n.length, which for numbers would always be undefined, so would always return true
if (totals == n) {
return secondVal
} else {
return -1
}
}
So the above reduces to this functionally identical code:
function digPow(n, p) {
let num = n.toString();
let total = 0;
for (let j = 0; j < num.length; j++) {
let power = p + j;
let indexs = num.charAt(j);
let Mathpow = Math.pow(indexs, power);
total += Mathpow;
}
let secondVal = total / n;
let totals = 1 / n;
if (totals == n) {
return secondVal
} else {
return -1
}
}
Now let's talk about the logic. The actual output will always be -1, unless the input is 1, due to what's clearly a logic error in the totals variable: the only case where 1/n == n is true is when n==1.
Setting that aside, and looking only at the secondVal variable, some examples of what it's calculating for a given input would be
digPow(123,1) --> (1^1 + 2^2 + 3^3) / 123 --> 14/123
digPow(321,2) --> (3^2 + 2^3 + 1^4) / 321 --> 21/321
digPow(92, 1) --> (9^1 + 2^2) / 92 --> 13/92
I'm pretty sure from your description that that's not what you intended. I'm not at all sure from your description what you did intend, so can't be much help in correcting the function beyond what I've done here.
What I'd suggest is to sit down and think through your algorithm first; make sure you know what you're trying to build before you start building it. There were some syntax problems with your code, but the real issues are with the logic itself. Your original function shows clear signs of "just keep throwing more lines of code at it until something happens" rather than any planned thinking -- that's how you wind up with stuff like "split a string into an array, then join it back into a string, then split that string into another array". Write pseudocode first: break the problem down into steps, think through those steps for some example inputs and make sure it'll produce the output you're looking for. Only then should you bust out the IDE and start writing javascript.

Categories