Need help to understand Steamroller solution 1

  // Loop over array contents
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      // Recursively flatten entries that are arrays
      //  and push into the flattenedArray
      flattenedArray.push(...steamrollArray(arr[i]));
    } else {
      // Copy contents that are not arrays
      flattenedArray.push(arr[i]);
    }
  }
  return flattenedArray;
};

// test here
steamrollArray([1, [2], [3, [[4]]]]);

Can someone helps me to understand this solution?
I can’t understand why after returning flattenedArray the code continues looping with the item’s array of the original array (arr).

If you are referring to the return statement:

return flattenedArray;

When the code reaches that statement the function immediately stops executing and it returns flattenedArray, so the code definitely does not continue looping. Also, the return statement is outside of the for loop and is the last line in the function, so it couldn’t continue looping if it wanted to :slightly_smiling_face:

If you still have a question about this solution then please ask again.

P.S. In the future, please include a link to the challenge.

2 Likes

I will try to explain with examples:
Before the first return statement the value of arr and flattendArray are:

arr: [2];
flattenedArray: [2];

and after the return statement the values are:

arr: [1, [2], [3, [[4]]]];
flattenedArray: [1];

I don´t understand why arr change its value.

OK, just to be clear, there is only one return statement in this code and it is the very last line of the function. This function is using recursion in the if block, perhaps that is what you don’t understand?

The array arr is not changing its value. The only thing that is changing its value is the array flattenedArray. The function is going through each element in arr, but it is not changing anything about arr.

I think it might help if you explain what you think this function is doing. Putting it into words is the first step in really understanding what is going on here.

Also, it might help if the entire code were pasted in here. You left out some important stuff at the top.

function steamrollArray(arr) {
  const flattenedArray = [];
  // Loop over array contents
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      // Recursively flatten entries that are arrays
      //  and push into the flattenedArray
      flattenedArray.push(...steamrollArray(arr[i]));
    } else {
      // Copy contents that are not arrays
      flattenedArray.push(arr[i]);
    }
  }
  return flattenedArray;
};

Actually, it might help to start with a simple example. Can you explain how the function works with the following function call?

steamrollArray([2,3])
2 Likes

I will share the link to the solution given from these exercise.
Solution
This topic is about the solution 1 given in the link.
Sorry if I am not explaining myself properly.

I understand this is solution 1. I’m trying to help you understand what it is doing. I suggested you start by explaining how the function handles the following:

steamrollArray([2,3])

Just explain it in words, no code needed. In case you are wondering, I am building to something bigger that I think will help you understand how this function works. But you need to completely understand the easier case where recursion is not used.

1 Like

it simply pushs 2 , 3 into flattenedArray because arr[i] is not an array.
In this case Array.isArray(arr[i]) return false and the code take the else path.
There is no recursion.

That’s a pretty good summary. I would add that the function loops through each item in the array passed into the function. I think you implied it, but I just wanted to make it clear.

So my summary would be, when the array [2, 3] is passed into the function then it loops through the array one item at a time, and since each of those items are not an array themselves (they are simple numbers) then the else block is executed for each number and the number is pushed onto the flattenedArray array and then when the loop is done, flattenedArray is returned.

In this specific case, if [2,3] is passed into the function then the array [2,3] will be returned. I want you to remember this, this is very important. I can’t stress it enough. You now know that when you pass [2, 3] into the function it returns [2, 3]. I’m serious, please remember this. Don’t make me have to remind you :slightly_smiling_face:

OK, now explain what happens, using the same amount of details I used above, when we call the function as follows:

steamrollArray([1, [2,3]])

It might help if you break your explanation up into loop iterations. For example, “the first iteration this happens” and “the second iteration this happens”.

1 Like

The function loop through each item.
arr[0] is pushed directly to flattenedArray because it is not an array.
arr[1] is an array so the function is called itself and then the function loop through each item of [2, 3].
Then arr[i] is not an array so it’s pushed into flattenedArray. Once the loop it is finished the return flattenedArray; is executed and from this point I just get lost.

You are getting lost because you forgot what I told you to remember.

Let’s look at the if block.

if (Array.isArray(arr[i])) {
  flattenedArray.push(...steamrollArray(arr[i]));
}

Let’s put in real values for the example we are using:

if (Array.isArray([2, 3])) {
  flattenedArray.push(...steamrollArray([2, 3]));
}

Are you with me so far? I just replaced the variable arr[i] with the actual value, which in this case is the array [2, 3].

That’s all you need. You don’t need to dig any further. You should be able to tell me what is happening here. I’ll repeat: What did I tell you to remember?

1 Like

The result of steamrollArray([2, 3]) is an array[2,3].
Due to the spread operator (…steamrollArray([2, 3])):wink: this is transform to (2,3) so
flattenedArray.push(…steamrollArray([2, 3])); is equal to flattenedArray.push(2, 3);

Perfect. So do you understand how steamrollArray([1, [2, 3]]) returns the array [1, 2, 3]? The first time through the for loop is just the number 1, so that is pushed onto flattenedArray. The second time through the loop we hit the array [2, 3] and thus we make the recursive call steamrollArray([2, 3]) to make sure it is flattened first so that we can then push it onto flattenedArray.

We already knew what steamrollArray([2, 3]) returns because we solved it previously. So in a sense, we cheated a little. In a recursive function, it is solved at the time you call it recursively. But the answer is the same. So when we get to the recursive call in the if block:

flattenedArray.push(...steamrollArray(arr[i]));

The function waits for steamrollArray(arr[i]) to execute and return an answer and then we can push that answer onto flattenedArray.

The key here is that we know steamrollArray will always return a flattened array. This may be the hardest part to comprehend. If the current item in the for loop isn’t an array then it can simply be pushed onto flattenedArray. But if it is an array, then we recursively call steamrollArray for that item to make sure it is flattened. In other words, we keep recursively calling steamrollArray until we have nothing but non-array items in the array we are passing to it. We are drilling down into each sub array until there is nothing but numbers.

I’ll try to clarify with some code.

steamrollArray([1, [2, [3,4]]])

There are two items in this array, the number 1 and the array [2, [3, 4]]. Don’t let the sub array [3,4] fool you. The initial array we are passing in only has two items.

First time through the for loop is the number 1 and so we merely push it to flattenedArray in the else block.

Second (and last time through the array) we have the array [2, [3,4]] and thus we make a recursive call in the if block.

flattenedArray.push(...steamrollArray([2, [3,4]]))

Don’t let the fact that we are making a recursive call here confuse you. It is as if we are calling a completely different function. Think of it as if we had a function called steamrollArray1 that does the exact same thing as steamrollArray. So at this point we have to wait for steamrollArray([2, [3,4]]) to return its value. I’m hoping at this point you have a fairly good understanding what will happen there, since it’s basically the same thing as the example we did above (steamrollArray([1, [2,3]]). Only once steamrollArray([2, [3,4]]) returns its value can we then complete the original line we were left waiting on:

// we are waiting here for steamrollArray([2, [3,4]]) to return a value
flattenedArray.push(...steamrollArray([2, [3,4]])) 
1 Like

Thank you so much for taking your time to explain me the solution.

1 Like