Const gets declared over and over again - recursivity - Steamroller

Tell us what’s happening:

[CODE IDEA SPOILER]

I created a recursive function to iterate through each element in the array and only push the element in the const newArr if it is not an array. I declared newArr as const so it wouldn’t get re-declared each time the function is called recursively, but it still does. Why does that happen? And how can I fix it?

Your code so far


function steamrollArray(arr) {
const newArr = [];

for (let i = 0; i < arr.length; i++) {
  
  if (!Array.isArray(arr[i])) {
    console.log(newArr);
    newArr.push(arr[i]);
    console.log(newArr);
  }
  else {
    steamrollArray(arr[i]);
  }
}
return newArr;
}

console.log(steamrollArray([1, [2], [3, [[4]]]]));
//console.log(steamrollArray([[["a"]], [["b"]]]));

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0.

Challenge: Steamroller

Link to the challenge:

1 Like

Remember function scope. Every time you invoke a function, that function has its own scope and the variables inside that function are declared for the scope of that function.

1 Like

you are not doing anything with this value

1 Like

Oh, I didn’t realize that. Thank you. Then I guess that my approach doesn’t work.

I thought that the value would be pushed in newArr, because it would eventually reach the if part. Doesn’t it work that way?

What you have to remember about recursion is that it is NOT the same function executing each time. The code is the same, but the state of the variables is different.

Imagine that instead of one function you created the same function with the same code for every execution you would need. In your case: steamrollArray1, steamrollArray2, steamrollArray3 etc.

You would replace the different calls so that steamrollArray1 called steamrollArray2 internally, steamrollArray2 called steamrollArray3, steamrollArray3 called steamrollArray4 etc.

This is really equivalent to what is happening with recursion. Technically there is a “stack” and whenever a function calls another function, the parameters and local variables are put on the stack while the internal function is running. If that function has an internal function, its parameters and local variables are put on the stack.

This continues until a function completes. At that point all of its variables are popped off the stack, and execution continues in the parent function.

This is what allows recursion to operate, in the same way that all functions operate. If you think about it in terms of separate functions with the same code but different parameters and local variables, hopefully it demystifies recursion.

1 Like

each time streamrollArray is called a new local variable called newArr is created. so, no, it doesn’t do that.

in that else statement the function should return the flattened array element, so what you need to do with the flattened array element?

1 Like

I think given an array of item and array of array of item, with different elements, this fn just return the flatten array.

@ieahleen, I tried to do what you said like this:

function steamrollArray(arr) {
  for (let i = 0; i < arr.length; i++) {
    if (!Array.isArray(arr[i])) {
      var newArr = newArr || [];
      newArr.push(arr[i]);
    }
    else {
      var newArr = newArr || [];
      newArr.push(steamrollArray(arr[i]));
      console.log('= ' + newArr);
    }
  }
  return newArr;
}

But it didn’t work. I’m obviously doing it wrong, but I have no idea where is my mistake.

@gizmola, oh, damn! It is so difficult to understand recursion… thank you for your thorough explanation and for taking the time to help me. I think I understand it a little better now, but I am still nowhere near to solving the challenge, hahaha.

look at the loop, at each iteration of the loop a new newArr is created. So you are pushing an element to newArr and then that is cancelled at next iteration of the loop
is that what you want?

if it was just a loop (no recursion) and you had to change a few of the elements, would you do that?

@ilenia I would either create a new array and push the elements I want to keep there, or splice the original array. But I have no idea how I could use recursion with splice, and also make sure I only leave the elements that are not arrays.

@ninjasun I think I didn’t understand what you explained. Could you explain again?

you want to keep all of them

the difference with recursion is that a few of these elements come from a function call.

just don’t redeclare newArr over and over inside the loop

If I declare the newArr variable outside the function, it doen’t get re-declared over and over again:

var newArr = [];

function steamrollArray(arr) {
for (let i = 0; i < arr.length; i++) {
  if (!Array.isArray(arr[i])) {
    newArr.push(arr[i]);
  }
  else {
    steamrollArray(arr[i]);
  }
}
return newArr;
}

console.log(steamrollArray([1, [2], [3, [[4]]]]));

Of course, I know it doesn’t have to be outside of the function for several reasons. But how I do to declare it only when the function is first called?

SOLVED! I solved it like this:

[SPOILER]

function steamrollArray(arr) {
  var newArr = [];
  function _steamrollArray(arr) {
    for (let i = 0; i < arr.length; i++) {
      if (!Array.isArray(arr[i])) {
        newArr.push(arr[i]);
      }
      else {
        _steamrollArray(arr[i]);
      }
    }
  }
  _steamrollArray(arr);
  return newArr;
}

console.log(steamrollArray([1, [2], [3, [[4]]]]));

good, but not the best you could do, You don’t need a second function.

why don’t you fix this by moving the newArr declaration out of the loop?

1 Like