What does continue do inside a nested for loop? - javascript

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;
}

Related

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)
}
}

Javascript does not exit for loop when return statement is called

While iterating through the for loop inside my function, even after the return statement is reached, the loop proceeds infinitely.
At this point, j is greater than lister.length. It exits the for loop and at the end of function jumps back to the for loop in a seemingly endless circuit.
This behaviour doesn't make sense to me as the return statement should terminate the function.
Here is my function:
function permutationLoop(originalArray, listOfPermutations) {
// generates a permutation(Shuffle),and makes sure it is not already in the list of Perms
var lister = generatingPerms(originalArray, listOfPermutations);
//adds the permutation to the list
listOfPermutations.push(lister);
var tester = true;
//This for loop looks through the new permutation to see if it is in-order.
for (var j = 0; j < lister.length; j++) {
//This if statement checks to see as we iterate if it is in order
if (lister[j] > lister[j + 1]) {
tester = false;
}
if (j == (lister.length - 1) && tester == true) {
//Return the permutation number that found the ordered array.
return listOfPermutations.length;
//THIS IS NOT EXITING THE LOOP
}
if (j == lister.length - 1 && tester == false) {
permutationLoop(originalArray, listOfPermutations);
}
}
}
may your if statement is not valid
try testing by if(true){ ..code.. }

Getting 'undefined', can't figure out why

Working my way through 'Eloquent Javascript' and I'm hitting a bit of a roadblock in understanding how to properly use if with for statements in the language. I'm supposed to write a function that counts all instances of the uppercase 'B' in a given string. The code I've written thus far:
function countBs(s) {
var counter = 0;
for (i = 0; i < s.length; i++) {
if ('B' == s.charAt(i)) {}
counter += 1;
}
}
console.log(countBs("BBC"));
expected output: 2
actual output: undefined
Is my loop going wrong, or my 'if'?
You have two bugs
You are incrementing your counter outside of the if statement.
You have no return statement.
The following can be used:
function countBs(s){
var counter = 0;
for(i = 0; i < s.length; i++){
if ('B' == s.charAt(i)) {
counter += 1; // this needs to be inside the if statement
}
}
return counter;
}
Your function does not have a return statement.
A few issues.
function countBs(s) {
var counter = 0;
for (i = 0; i < s.length; i++) {
if ('B' == s.charAt(i)) {
++counter;
}
}
return counter;
}
document.write(countBs("BBC"));
You were not returning counter at the end of the function
Your if statement was opened, then immediately closed, so nothing happens if the character was B
Even if you returned counter and fixed the above 2 errors, the function still would have exited after 1 B was found. To fix this, move the return after the for ends.
If you're interested, the same problem can be solved with this one-liner:
function countBs(s) {
return s.match(/B/g).length;
}
document.write(countBs("BBC"));
Which finds all B characters (case-sensitive), puts them into an array, then returns how many items are in that array.

Short way to write a long series of if-else-if's?

How to do two variables in an if condition? Here I have few else ifs and I want a 100 else ifs! Is there a shorter way?
$(document).on('click', '.btn-next', function () {
var z = [];
var recipientsArray = z.sort();
var zDuplicate = [];
$('option:selected.exclude_global').each(function() {
z.push($(this).val())});
for (var i = 0; i < recipientsArray.length - 1; i++) {
if (recipientsArray[i + 1] == recipientsArray[i]) {
zDuplicate.push(recipientsArray[i]);
}else if(recipientsArray[i + 2] == recipientsArray[i]){
zDuplicate.push(recipientsArray[i]);
}else if(recipientsArray[i + 3] == recipientsArray[i]){
zDuplicate.push(recipientsArray[i]);
}else if(recipientsArray[i + 4] == recipientsArray[i]){
zDuplicate.push(recipientsArray[i]);
}
}
if(zDuplicate.length>>0){
alert("Global Filter Already Exists");
event.preventDefault();
}
});
Here I have few else ifs and I want a 100 else ifs! Is there a shorter way? I have a dynamic table with dynamic rows. when my table has 5 rows the code is working, but when I have more its not working.
What you're looking for is called a nested loop. You basically can write a loop within a loop. (As many as you want, actually. Though it can get ugly fast.)
Consider your loop structure:
for (var i = 0; i < recipientsArray.length - 1; i++) {
// check if recipientsArray[i] equals any other element
}
Well, that's just another loop:
for (var i = 0; i < recipientsArray.length - 1; i++) {
for (var j = i + 1; j < recipientsArray.length - 1; j++) {
if (recipientsArray[j] == recipientsArray[i]) {
zDuplicate.push(recipientsArray[i]);
break;
}
}
}
Note that there's probably a more efficient way of checking for duplicates. (Especially if the collection is sorted.) At the very least I've changed the logic so you're not re-comparing comparisons you've already made. (I did this by starting the inner loop at i + 1 instead of 1 as your logic does.)
I also think I've replicated your else if results by using a break statement. Since your else if logic basically means "once you find one, stop looking". That's what this break should do, or at least is intended to do, but you'll want to test that. If it doesn't (nesting can be confusing sometimes, which is why it should be done carefully) then you can probably make use of labels to achieve the same effect.
Ultimately, however you implement it, the concept is the same. You're asking how to iterate over multiple values in an array. That's what a loop is for.
I don't know that language. But data and control structures are data and control structures in any language.
Substitute your for loop by :
for (var i = 0; i < recipientsArray.length - 1; i++) {
for ( var j = i+1; j < recipientsArray.lenght-1; j++) {
if (recipientsArray[i] == recipientsArray[j]) {
zDuplicate.push(recipientsArray[i]);
break;
}
}
}
Thank you so much for the idea!
A small change to your code works like heaven!
for (var i = 0; i < recipientsArray.length - 1; i++) {
for (var j = 1; j < 100; j++) {
if (recipientsArray[i+j] == recipientsArray[i]) {
zDuplicate.push(recipientsArray[i]);
break;
}
}
}

When does this for loop escape?

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.

Categories

Resources