When does this for loop escape? - javascript

To check my understanding, do we have that the following for loop never escapes only if row.length < n (otherwise, the loop can escape)?
function someFunction (matrix,n) {
for (var i = 0; i < n; i += 1) {
var row = matrix[i];
for (var i = 0; i < row.length; i += 1) {
if (row[i] < 0) {
alert("Something's wrong");
}
}
}
}

Do not use the same incrementing variable in nested for loops!
function someFunction(matrix,n) {
for (var i = 0; i < n; i += 1) {
var row = matrix[i];
for (var i = 0; i < row.length; i += 1) { //VERY BAD!!!
if (row[i] < 0) {
alert("Something's wrong");
}
}
}
}
When the inner loop completes the first loop, i will equal row.length. This will also complete the outer loop, which increments i again by 1. Thus, when the outer loop goes to begin its second iteration, you will have i=row.length+1. Do this instead:
function someFunction(matrix,n) {
for (var i = 0; i < n; i += 1) {
var row = matrix[i];
for (var j = 0; j < row.length; j += 1) { //using j instead of i
if (row[j] < 0) {
alert("Something's wrong");
}
}
}
}

It's bad practice to use the same loop counter i for the inner and outer loops. That's just confusing and leads to unpredictable behaviour.
But since you have done so and you want to know what will happen:
When the inner loop finishes for the first time, i will have the value of row.length from the first row in your matrix. i will then be incremented by the outer loop. If this new value of i is >= your n variable then the outer loop will end immediately. Otherwise the outerloop will continue with the new value of i and execute this line:
var row = matrix[i];
At that point if i is greater than or equal to matrix.length the row variable will be undefined, so then when you get to the inner loop and try to test row.length you are testing undefined.length which will give you an error and stop execution.
But if i is less than or equal to matrix.length then the inner loop would "work" in the sense of running again with the new value of row and with i set back to 0 for its first iteration.
If the previous row's length happened to be same as its index minus 1 then the same row would be processed over and over forever.
So essentially every iteration of the outer loop is selecting a more or less random (and possibly undefined) row to continue with based on whatever the length of the previous row was.

Related

breaking a for loop with length decrement

I found this code to convert an excel column name into a column number but having a hard time understanding the break condition for the loop
//function convert excel sheet column to number
toColumnNumber = (colName) => {
let result = 0;
for (let i = colName.length, j = 0; i--; j++) {
result += Math.pow(26, i) * (colName.charCodeAt(j) - 64);
}
return result;
};
console.log(toColumnNumber("AB"));
it uses i-- as a break condition and i can't understand how it can be used to break the loop. or is it just that is how javascript works when we use i-- as a break condition and it reaches 0 it breaks the loop?
As we keep decrementing the value of i, eventually it reaches 0 and that would be falsy and would stop the loop.
This is just a fancy way of doing:
for (let i = colName.length, j = 0; i > 0; j++, i--) {
result += Math.pow(26, i) * (colName.charCodeAt(j) - 64);
}

Why is the loop not iterating for compounding investment calculation in JS

I'm writing a function to calculate investment return over period of years. However, the function seems to be only able to calculate for one year. If the totalyears is more than 1, the loop as shown below is not iterating and it returns wrong value.
const calc = (initial, monthlyContribution, totalyears, annualisedReturn) => {
let sum = initial;
for (i = 0; i < totalyears; i++) { // ISSUE: THIS NOT LOOPING WHEN totalyears > 1
let balance = sum;
let totalBalance = 0;
for (i = 0; i < 12; i++) {
totalBalance = totalBalance + balance;
balance = balance + monthlyContribution;
}
sum = balance + (totalBalance / 12) * (annualisedReturn / 100);
}
return sum;
};
console.log(calc(0, 100, 2, 10)); // This return 1255 which is wrong
You're using the same global variable for both loops. i will have the value 12 when leaving the inner loop, thus the condition of the outer loop will be false
You are using the same variable "i" in the inner loop and you are not declaring it again.
So when you start the loop with i=0, your inner loop will first make i=0 again, then it will increase until i=12, and then the same variable is used in the first loop, so it will go from 0 to 12, skipping iterations. Use "i, j,k" for nested loops.
Something like this:
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
}
}

i++ loops without any problem, i+2 loops infinitely and crashes

I want to create a simple loop function that adds 2 every time it loops. However, even though I tell my for loop to stop if the number reaches or is less than 100, it goes past 100 and loops infinitely.
i++ works just fine:
function addTwo() {
for (i = 0; i <= 100; i++) {
console.log(i);
}
}
addTwo();
When I change it to i+2 it crashes:
function addTwo() {
for (i = 0; i <= 100; i + 2) {
console.log(i);
}
}
addTwo();
I expect the console to log:
0
2
4
6
8
...
100.
But instead it loops infinitely and crashes.
i+2 in your case does nothing. JS evaluates it and then does nothing with the calculated value, this means that i is never increased.
++ is a special operator that increments the variable preceding it by 1.
To make the loop work you have to assign the value of the calculation i+2 to the variable i.
for (i=0; i<=100; i = i+2) {
console.log(i);
}
or
for (i=0; i<=100; i += 2) {
console.log(i);
}
i++ increments i. But, i+2 doesn't update the value of i. You should change it to i += 2
function addTwo() {
for (i = 0; i <= 100; i += 2) {
console.log(i);
}
}
addTwo();
The third parameter of a for is the final-expression:
An expression to be evaluated at the end of each loop iteration. This occurs before the next evaluation of condition. Generally used to update or increment the counter variable.
In your case you are not assigning any value to i. You should replace it with something like this:
function addTwo() {
for (i=0; i<=100; i+=2) {
console.log(i);
}
}
addTwo();
i++ is a short hand for i += 1 which is called Increment Operator But i+2 or even i+1 will not increase the value of i. You need to increase it by assigning a new value to i. i = i + 2 or i += 2.
Number is one of the primitive types in javascript which mean you can't change it unless you use assignment operator =
Note: You are not using let or var with i this will make i a global variable.
function addTwo() {
for (let i = 0; i <= 100; i+=2) {
console.log(i);
}
}
addTwo();
for (i = 0; i <= 20; i++) {
console.log(i);
i++;
}
You can increase i twice Or
for (i=0; i<=100; i+=2) {
console.log(i);
}
you can use i+=2 it will increase value of i 2 times and set new value of i.

javascript while loop correctly iterating but for loop with same logic is not, on array with integer values and some null values in there

Iterating through a javascript array which has some data in, and some null or not defined values also, is giving funny behaviors with a for loop, but not with a while loop. It is not returning when it should and is stuck in an infinite loop
I have investigated the outputs extensively, the condition whether the number exists in the array is never evaluated to be true, only ever false, but it sometimes enters the if statement region as if it is true. It is seemingly arbitrary.
//function called within this code
function randomArrayOfIndexes() {
var randNumbArray = new Array(4);
var indexToAssign = Math.floor(Math.random() * Math.floor(4));
randNumbArray[0] = indexToAssign;
for (i = 1; i < randNumbArray.length; i++) {
indexToAssign = Math.floor(Math.random() * Math.floor(4));
while (arrayContains(randNumbArray, indexToAssign)) {
indexToAssign = Math.floor(Math.random() * Math.floor(4));
}
randNumbArray[i] = indexToAssign;
}
return randNumbArray;
}
//this works
function arrayContains(arrayin, numberIn) {
var i = arrayin.length;
while (i--) { //takes one from i so highest index is accurate on first iteration
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
//this doesn't... not even backwards like the above iteration
function arrayIncludes(arrayin, numberIn) {
for (i = 0; i < arrayin.length; i++) {
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
At first each function above is passed in an array with [int value, null, null, null], and a random number; when the function returns, the next null value is filled with the random number that doesn't exist in it already, so [int value, int value, null, null]... until all values are filled... the final array is filled with unique random numbers from 0 to 3, to provide an index for a piece of data in another array... to make sure that it is only used once in the program I am writing.
I would expect it to return true if the number passed in is already in there, another random number then generated outside of the broken function, and the process repeated until a unique random number is found. When it is found, the array being passed back in will be populated at the next available index, and the process repeated. This is not happening. It is getting stuck in an infinite loop, and never returning
you are just missing a var before i:
function arrayIncludes(arrayin, numberIn) {
for (var i = 0; i < arrayin.length; i++) {
// in ^ here
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
You may also declare it before loop, like
var i;
for (i = 0; i < arrayin.length; i++) {
...
By the way, this way of generating random numbers without duplicates is very inefficient, I suggest something like having an array of 0-3 (in your current example) or 0-n and then just randomly taking items out of it. then you don't have to loop through the whole array each time you find a new number. every time you just find a random index between 0 and the length of remaining items.
Imagine that the array length is 1000, and the last item remaining is a number like 100, how many times you have to find a random number and loop through whole array till your random number is 100?
var n = 5;
var a = new Array(n);
for(var i=0;i<n;i++) a[i] = i;
var result = new Array(n);
var i = n;
while(i)
{
var index = Math.floor(Math.random() * i);
result[--i] = a[index];
a.splice(index,1);
}
document.getElementById('a').innerHTML = result;
<div id="a"></div>
You need to declare variables in you loops with for i=0. if you don't do this the variable is global and when you use the same loop variable in nested loops one can change the other.
You are using i in both loops so when you call the for loop with:
function arrayIncludes(arrayin, numberIn) {
for (i = 0; i < arrayin.length; i++) {
// etc
}
You set i back to 0 ad iterate it — this is the same i you are using in randomArrayOfIndexes so it interferes with that loop. This is a common cause of hard-to-find bugs and is hy you should always declare loop variables.
Here's the bug in it's simplest form. Notice that the out loop only runs once because i is incremented in the inner loop causing the outloop to exit early:
for (i = 0; i < 4; i++){
console.log("out loop number: ", i)
for (i = 0; i < 4; i++){
console.log("inner_loop: ", i)
}
}
If you declare the variables for for let i =, each loop gets its own version of i both loops run independently:
for (let i = 0; i < 4; i++){
console.log("out loop number: ", i)
for (let i = 0; i < 4; i++){
console.log("inner_loop: ", i)
}
}

What does continue do inside a nested for loop?

I have the following code:
for (var i in players) {
for (var x in players[i].bullets) {
for (var y in xpBoosts) {
if (something === true) {
// do something
continue;
}
}
}
}
What will the continue statement do? Will it cycle the innermost for loop or the outermost?
Is there any way I can get the continue statement to cycle through to the next bullet?
continue terminates the current iteration of the loop it's in. To terminate the iteration of another loop, use it with labels:
for (var i in players) {
bullets: for (var x in players[i].bullets) {
for (var y in xpBoosts) {
if (something === true) {
// do something
continue bullets;
}
}
}
}
In your particular code continue doesn't do anything.
continue is a keyword that will quit the current iteration of the loop and carry on with the next.
as an example:
for (i = 1; i <= 10; i++) {
if (i == 5) continue;
console.log(i);
}
You'll notice that 5 is not printed to the console. When the conditional check is proven true, it continues onto the next iteration without performing the rest of the code in the block.
By default, continue and break apply to the innermost loop. In your particular code, it will continue this loop:
for (var y in xpBoosts) {
However, this behavior can be customized through labels. For example:
outerLoop:
for (var i = 0; i < someVal; i++){
middleLoop:
for (var j = 0; j < someOtherVal; j++){
innerLoop:
for (var k = 0; k < yetAThirdVal; k++){
continue;//skip to next iteration of innerLoop
continue innerLoop;//skip to next iteration of innerLoop
continue middleLoop;//skip to next iteration of middleLoop
continue outerLoop;//skip to next iteration of outerLoop
}
}
}
Hope this helps!
EDIT: I'll leave my answer here, but I much prefer ohlec's answer.
continue only moves on to the next iteration of the innermost for loop.
You could have a variable that is initialized as false for each bullet. You can then mark this to true if you continue the inside loop.
for (var x in players[i].bullets) {
var skipThisBullet = false;
for (var y in xpBoosts) {
if (something === true) {
// do something
skipThisBullet = true;
continue;
}
}
if (skipThisBullet) continue;
}

Categories

Resources