Use Caution When Reinitializing Variables Inside a Loop Question

Tell us what’s happening:
Hi All,

I understand the model answer but i just want to understand why this output is caused simply because row array isn’t resetting(global variable).

From my understanding, the first iteration of outer loop will end after inner loop runs twice, row is pushed to newArray, then outer loop begins to start second iteration. So my question is why does the extra columns come from? How does the loop know when to start a new row?

[
[0][0] <—first iteration of outer loop
[0][0] <—second iteration of outer loop
[0][0] <–third iteration of outer loop
]

Your code so far


function zeroArray(m, n) {
  // Creates a 2-D array with m rows and n columns of zeroes
  let newArray = [];
  let row = [];
  for (let i = 0; i < m; i++) {
    // Adds the m-th row into newArray
    
    for (let j = 0; j < n; j++) {
      // Pushes n zeroes into the current row to create the columns
      row.push(0);
    }
    // Pushes the current row, which now has n zeroes in it, to the array
    newArray.push(row);
  }
  return newArray;
}

let matrix = zeroArray(3, 2);
console.log(matrix);

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/debugging/use-caution-when-reinitializing-variables-inside-a-loop

It doesn’t actually work – I ran this on a dev system, and on jsFiddle (basically somewhere outside of the FCC test page), and the result is the same: I get an array of three elements, each containing SIX elements – so three copies of the full row variable.

Instead, the row variable should be moved inside the outer loop so it resets every time.

I have both versions running side-by-each here.

I find myself wondering why the row variable is completely populated at each iteration, still tinkering with it. One thing I highly recommend, when stuck on something like this, is that you get familiar with the Chrome Dev Tools (or some sort of dev tools, that will allow debugging). In Chrome’s, when you click on the ‘Sources’ tab, you can add breakpoints where execution pauses and you can inspect values of various elements. Doing this, you can see each member of the newArray being incremented in the loop as you’ve written it.

2 Likes

The row is fully populated because every element in newArray is a reference to the same object.

Try this:

let arr1 = [1, 2, 3];
let arr2 = arr1;

arr2.push(4);
console.log(arr1); // [1, 2, 3, 4]

arr1 has been changed.
That is because arr2 is not a new array, just a reference to the same object as arr1.

Something similar happens in the posted code. When you change row in the next iterations, they also change the previous elements of newArray which are row as well. :slight_smile:

3 Likes

Makes sense. I wasn’t sure if they were being passed by reference, or passed by value. Thanks, @EdMagal!

huh. And here’s one answer.

Thanks all for the response, i understand how the each row has 6 elements, because the inner loop is iterated 3 times, but why would there be 3 rows then? Sorry this seems like a stupid question but i just cant see through it.

My thought process is outer loop starts at 0, inner loop iterates twice to satisfy “j < n” then pushes the row into newArray, then outer loop starts at 1 and rinse and repeat. I don’t see how new rows are populated . I understand that row array is a global variable so its saving all the previous iterations of [0,0] but it should be pushing to the same row. So my question is how is there 3 rows in total? I thought the outerloop loops three times for [0,0}.

Thanks,

The outer loop simply pushes an instance of rows[] onto the newArray[]. And it loops three times. So three times, you push a copy of rows.

But the point of the conversation regarding pass by value or pass by reference, while the rows variable is assigned by value, it’s contents (it seems) are handled by reference. So when the rows variable is updating, its reference at a global level is also updating each ‘copy’ in the newArray.

So initially, newArray = [] and rows = []. After the inner loop has completed the first time, newArray is still empty, but rows = [0,0]. At that point, rows gets pushed onto newArray, which makes newArray = [ [ 0,0 ] ]. Note that newArray is not a copy of rows – it is an array, of which its sole element is a reference to another (nested) array.

Now, the second outer loop begins. At the end of the inner loop, newArray = [ [ 0,0 ] ] and rows = [0,0,0,0]. As that has updated, it has updated the first reference in newArray, so when we push another copy of rows onto newArray, we get newArray = [ [0,0,0,0], [0,0,0,0] ] androws = [0,0,0,0]`.

Third time through the outer loop, rows updates as we go through the inner loop, but it also updates the references in newArray – so before we push rows onto newArray, it has already changed! It now looks like newArray = [ [0,0,0,0,0,0], [0,0,0,0,0,0] ] (two members, each a reference to rows, each six elements long). After we push ANOTHER copy of rows onto it, we get:

newArray = [ [ 0,0,0,0,0,0 ], [ 0,0,0,0,0,0 ], [ 0,0,0,0,0,0 ] ]
rows = [ 0,0,0,0,0,0 ]

In other words, newArray only contains references to that rows array. When the outer loop executes three times, it pushes that reference on three times. Rows, on the other hand (so long as you leave it in a global scope), continues to accumulate members, rather than re-initializing each iteration. That’s because the INNER loop, which is the only one changing rows, keeps pushing elements on. But that inner loop executes six times (twice for each inner loop, times three for the outer loop). Thus, rows ends up with six members.

8 Likes

Wow, that got overthought. Again, if you pull up the ‘Sources’ pane in the console, and add a breakpoint somewhere within both the inner and outer loops, you can watch the values as they change.

@snowmonkey thank you very much for the detailed response, i get it now! Appreciate your patience lol once i understand how to troubleshoot with browser console this would be much less painful!

Hahaha – it’s all about time and experience. Loops, and particularly nested loops, can get complicated. Also, you’re throwing in variable scope, which is in itself a complex topic.

Glad I could help.