Problem with nesting for loops

i struggled with this one too but your explanation helped me to understand it better. This is how i understand this now!

/*
first i loop end up in [1,2]
executes j for the lentgth of [1,2] (arr[i].length)
first loop product = product * arr[i][j] is executed (1x2)
second loop (2x3)
third loop i moves to the 2nd sub-level and product = (3x4)
This continues untill the end!
Total sum is 1*1*2*3*4*5*6*7 = 5040
*/

aas

It is hard explanation for beginners. They will not understand.

so it loops through the first for loop, goes into the embedded for loop and stays there until it is satisfied and then goes back out to the outer for loop? is that how it works? if that makes sense.

thanks,

Allen

How I understand it is that the first element in the first subarray of the array is 1 so it multiplies the variable “product” by 1, giving the answer 1. Then the next element in the first subarray of the array is 2 so it multiplies variable “product” by 2. Then the function iterates to the second subarray, where the first element is 3, so it mutiplies “product” (which currently equals 2) by 3, which gives 6. Then the function iterates tot he second element in the second subarray of the array and mulitplies “product” by 4, which gives 24. And so on.

This thread was extremely helpful. I don’t know about anyone else, but its kind of like I’m able to figure this stuff out, but I’m not so sure I’ll be able to retain it all.

1 Like

So I really struggled with this, and as a visual learner, couldn’t understand the written answers, so I drew out this and then thought it might be helpful to others… :slight_smile: here goes.

Array = ([[6,7],[8,9],[10,11,12]]);
i length = 3 (there are three sub-arrays)
j length = 2,2,3 (each sub-array contains those many items respectively)
* I changed the values because to make it clearer
** Cool a-ha thought - length starts at 1 for counting, but index starts at 0, so index will never equal length in an array :astonished:

This is the map for the not-really-code below

i = 0 // telling it to start with the first set of [ ], 
    i<arr.length // TRUE (i = 0 and length = 3)
j = 0  // goes to the first item in the first sub-array
   j <arr[0].length // TRUE (j = 0 and length = 2)
      ij // product * the value at location[0][0] = 1 * 6 
      j++ // increase j by one so now j = 1
   j <arr[0].length // TRUE (j = 1 and length = 2)
      ij // product * the value at location [0][1] =  6 * 7
      j++ //  so  j = 2 
    j <arr[0].length // FALSE (j = 2 and length = 2) -  EXIT FIRST INNER LOOP

i++ // i = 1 aka the second sub-array - START SECOND OUTER LOOP
    i < arr.length // TRUE (i = 1 and length = 3)
j = 0 ; j<arr[1].length // TRUE (j resets to 0 for each new inner loop)
    ij // product * value at location[1][0] = 42 * 8
j = 1 ; j<arr[1].length // TRUE
    ij // product * value at location[1][1] = 366 * 9

//... (continue around and around)

j = 2 ; j<arr[2].length // TRUE (this is the last one)
   ij // product * value at location[2][2] = 332,640 * 12
j = 3 ; j<arr[2].length // FALSE - EXIT INNER LOOP
i = 3 ; i<arr[2].length // FALSE - EXIT OUTER LOOP
  return product = 3,991,680

This would work for any nested loops really, changing any of the for ([initialization]; [condition]; [final-expression]) results in the same loops, just different [start point]; [what determines the TRUE/FALSE]; [what happens at the end of each loop]. Adding more arrays or sub-arrays is just more info. Different ij, is just different math…
Adding a third loop, well, :cloud_tornado::cloud_tornado::cloud_tornado:

I’m a newbie so PLEASE let me know if I’ve made any mistakes here or if something is misleading, I used about 5 sources to figure this out in a way that would get me predictable results testing under different constraints but I could be way off :sweat_smile:

2 Likes

Still having a hard time wrapping my head around this. If we’re starting on the first loop where i = 0, then you’d be looking at the 1st element [1, 2] and the 1st element of that subset, 1. In this 1st step, product = 1 so it would be 1 * 1 = 1. After that runs, the loop would run again, so i = 1. That would be the 2nd element of the array [3, 4] and the 2nd element of that subset, 4. When the loop runs again, i = 2, so the 3rd element of the array would be [5, 6, 7], and the 3rd element of the subset, 7. Basically, I’m just not sure how the answer 5040 gets spit out.

it might help to change the “elements” to kindof clear things up…
so instead of [1,2][3,4]…
use [a,b][c,d][e,f,g]

for(var i=o; i<arr.length; i++) basically means for variable starting at index 0; as long as the index is less than the total number of arrays keep going; each time add one to look at the next index
for(var j=0; j<arr[i].length; j++) means for variable starting at index 0; as long as the index is less than the length of the i array it’s in keep going; each time add one to look at the next index

so: i= 0, j = 0 —> a
then i = 0, j = 1 ----> b
it tries i = 0, j = 2 but that doesn’t exist, so only then i++
now i = 1, j = 0 ----> c
then i = 1, j = 1 ----> d
it tries i = 1, j = 2 but that doesn’t exist, so then i++
now i = 2, j = 0 ----> e
then i = 2, j = 1 ----> f
then i = 2, j = 2 -----> g
it tries i = 1, j = 3 but that doesn’t exist, so then i++
it tries i = 2, j = 0 but that doesn’t exist either, so it exits

this gives you product *= (a * b * c * d * e * f * g)

If you look at the above picture, the idea is that it goes into the first loop (blue)(which is set by the first for…) and that carries it right into the second loop (pink)(set by the second for…) and keeps going around the pink look until it gets a FALSE (j<arr[i].length) which puts it back into the blue (i++ is when i goes from 0 to 1), then back into the pink…

Think about it like you’re looking for all of a specific product to gather as much of as you can, lets say it’s a new fancy phone, cuz you have one and you know you can resell them for lots of $$$.
So you drive to Smallville (i=0) and check all the stores (j = 0, 1) filling your trunk with boxes of phones. Then drive to the next town, Springfield (i = 1), and check all the stores there (j = 0, 1), filling your trunk even more. Of course you wouldn’t drive to a town, check a single store, then go to another town, you’d miss out on phones! You continue on, until there are no more cities to drive to or stores to check, then you celebrate (product* all the phones) by rolling around in a big pile of phones.

Does that help?!

1 Like

@Unabashedley that clears it up! Thanks for your help. The way I was thinking about it was i & j would increase 1 after the first loop ran. So after you got 1 (or “a” in your example), both number would increment, so i & j = 1. I didn’t realize the subset loop keeps running until it was no longer true. Just out of curiosity, if we added “break” after the 2nd loop, would that cause it to stop running after the 1st interation?

@icrams Do you mean


function multiplyAll(arr) {
var product = 1;
    for (var i = 0; i < arr.length; i++) {
      for (var j = 0; j < arr[i].length; j ++) {
        product *= (arr[i][j]);
        break; //here
      }  
     break;  //or here??
}    return product;  }

The thing to keep in mind, is the break will affect the loop whose brackets it’s in - if you break after one iteration (loop) of the pink loop, it still iterates the inner blue loop completely until it gets a false; if the break is in the brackets for the blue loop, it will only iterate through blue once per iteration of the pink loop (which goes until it gets a false).

Okay, that might be confusing. :thinking:

Using the phone shopping spree example - if you break after one store in each city (to keep suspicions down of other shoppers) (aka the pink loop aka j) then you get to every city, but only the first store in each. If you break (your boss calls and tells you to get back to work) after the first city, then you only have what you collected in that city.

If you want to try out different versions, like changing the value of j or i etc, then this might help:
https://goo.gl/mr468z it will go through exactly what is happening step by step.
Try changing j++ to j +=2 or i = 0 to i = 1
or for real fun, change the

product *= arr[i][j]; // to 
product += arr[i][j]; // and use
  multiplyAll([['a','b'],['c','d'],['e','f','g']]);

:nerd:

@Unabashedley I think I get what you mean. Just gotta let it sink in a bit. But thanks for all your help!

@icrams NP! It helped me figure it all out even more! :+1:

That was an incredible and delectible anology. Love it!

1 Like

I’ve got to say, this has been really a really helpful post for me. I’ve been advancing without fully grasping the concept of loops and understanding how they work exactly and so, on algorithm challenges, I’ll figure out how to resolve them but I’ll trip up with my use of loops and I’ll be stuck for hours not on the challenge itself as I’ve long since come up with a solution but the implementation of looping and reaching all the various aspects in the correct order that has long been a problem for me.

This post has been very useful and for the past hour or so, I’ve been playing around with a loop based on 'Unabashedley’s theory using letters rather than numbers and I just console.logged different variations which gave me a few ‘a-ha’ moments.

I’ll share in the hope that it might help others who have had the same problem as me.

I used the full alphabet and ten sub-arrays and I think the longer nature of the array helped me a little more.

var alphabet = [["a","b"],["c","d"],["e","f","g"],["h","i"],["j","k"],["l","m","n"],["o","p"],["r","s"],["t","u","v"],["w","x","y","z"]];

At first, I just used one for loop ‘i’ and looped through with ‘i’ and that just counted my array length 0-9.

for(var i = 0; i < alphabet.length; i++){ console.log(i); }

By adding the ‘i’ to alphabet[i], that accessed or pointed to, each of the sub-arrays: [“a”, “b”], [“c”, “d”] etc.

for(var i = 0; i < alphabet.length; i++){ console.log(alphabet[i]); }

To get inside the sub-arrays, I added a second loop ‘j’ and to begin with, I just wanted to see what happened with each loop individually before I went any further, so I first console.logged ‘i’. That printed out the index of the sub-array by the number of items that it contained because of the second loop ‘j’. The first sub array contained [“a”, “b”] this was at index 0 and because the ‘j’ loop went through it twice, ‘i’ logged 0,0 because ‘j’ makes two loops, then 1,1, then 2,2,2 etc. Even though we’re not logging ‘j’ it still plays it’s part and loops through everything that ‘i’ loops through.

for(var i = 0; i < alphabet.length; i++){ for(var j = 0; j < alphabet[i].length; j++){ console.log(i); } }

This was the first ‘a-ha’ moment and for the first time, my frustration with loops subsided a little, so I continued. Now, I logged ‘j’ but this time, before running it I tried to mentally figure out what was going to happen and I predicted it correctly. As ‘i’ looped through the sub-array and printed it by the number of times of the inner loop ‘j’, logging ‘j’ did the opposite, well kind of - it logged the index of the contents of each sub-array, so sub-array[0] logged 0,1 as there were two items inside; sub-array[1] also logged 0,1; sub-array[2] logged 0,1,2 because there were three items and so on…

for(var i = 0; i < alphabet.length; i++){ for(var j = 0; j < alphabet[i].length; j++){ console.log(j); } }

Then I tried logging ‘i’ and ‘j’ together and that logs both values side by side:
0 (sub-arr index[0]), 0 (content of sub-arr index[0])
0, 1
1, 0
1, 1
1, 2
2, 0 and so on.

for(var i = 0; i < alphabet.length; i++){ for(var j = 0; j < alphabet[i].length; j++){ console.log(i, j); } }

Finally, I added both loops to the alphabet array along with a string narrative to help me visualize everything that was going on.

for(var i = 0; i < alphabet.length; i++){ for(var j = 0; j < alphabet[i].length; j++){ console.log("This is the outer loop 'i' checking the outer level array at index [" + i + "] and this is the second loop, the inner loop 'j' checking the sub-level arrays at index [" + j + "]. As for our alphabet array, that would be letter " + alphabet[i][j]); } }

I wouldn’t say I’ve conquered loops as such but I’ve made a significant break-through or at least it feels that way at this moment and hopefully it helps someone else too.