What am I missing on Steamroller?

Tell us what’s happening:
I did the below right off the bat. It seems logical to me. It shrinks the nested arrays down to a simple 1-D array, right?

What am I missing here?

In the hint it suggested using .isArray(), but I don’t understand that at all. I know these are arrays. I read through the doc on MDN and I don’t quite get where the .isArray() suggestion is coming from?

Again, what am I missing here?

Your code so far


function steamrollArray(arr) {
  let args = [];
  args.push(arr)
  console.log(args)
  return args;
}

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

Your browser information:

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

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/steamroller

You know you’re being passed an Array, yes – but do you know if the current member of the array is itself another array? Looking at your code:

let args = []; // so args is an empty array...
args.push(arr); // and onto that you've pushed exactly the array you were passed.

So, rather than taking (for example):

[1, [2, 3, [ [ [ 4 ] ] ] ] ]

and turning it into:

[1, 2, 3, 4]

(a single-level array), instead, you create an array and cram the existing array into that. In essence, you’ve added another layer deep to the array structure. If you watch this in the chrome console, you will see that it becomes a deeply nested array.

By using Array.isArray(...) on each member of the array, you’re asking “Is the current member an array? If it is, then we need to do all this same stuff to THAT one too.” And the beauty of the recursive hint, it doesn’t matter how deeply nested it is. It simply drills to the point where Array.isArray(...) finally returns false, saying “Nope, this one’s not an array, so do something else.”

1 Like

another helpful hint is getting into the habit of using function tracers when you are stuck. they are great teachers and give us immediate feedback that we can compare with what we think is happening.

as an example…

function steamrollArray(arr) {
  let args = [];
  args.push(arr)
  console.log(args)
  return args;
}

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

your provided code (above) outputs 1,2,3,4

but if we change your console.log statement as follows…

console.log(args[0]);

you will notice your output is still 1,2,3,4 when what we are expecting is 1 (because the goal is to flatten the array) suggesting that the first element of the array is an array. following through this logic you will come to the following…

console.log(args[0][2]);

which will output 3,4 meaning the third element of this nested array contains yet another nested array. we could continue to console.log(args[0][2][0]) but hopefully by now you can see what is actually happening.

you have to know where to place them in your code and what questions to ask to get the answers you want but once you do youre golden.

the key is asking th right question, such as…

this is the right question. that is, what am i expecting?. well, you are expecting a flattened array, so your output should be a 1 dimensional array with 4 elements with value 1-4. using console.log to verify that methodically and you will always uncover where the error is.

be mindful, the freecodecamp console window has a limit of what its willing to show you if the output is too excessive.

1 Like

Instead of what @rekurzionis advising there, which is completely correct, you can use
console.log(JSON.stringify(args))
So you will see immediately if it is a monodimensional array or not

2 Likes

The other advantage to this approach is when you console.log an array and then update the array, the console updates to match. This approach gives a static snapshot of an array or object.

2 Likes

Thanks for the suggestion. Cataloging the different elements of the subarrays according to their index number really helps.
My idea for solving it is to use array.prototype.flat() and apply it to different index numbers and push those values onto an empty array and then return that array as a 1-D.
I have an inkling that there’s something that won’t work about this but I can’t quite put a finger on it. Am I missing a much simpler technique?
I heard recursion mentioned earlier when speaking of isArray().
Should I be using isArray and pushing values from those elements (that register as arrays) into an empty array?

my suggestion is to solve it the way you understand it first. try things. go through the iteration of building your bent pyramid until you figure out how to build a world wonder.

make it readable and clear what you are doing. have concise documentation in your code including the code itself being clear. understand how you are solving the particular problem. what the problem is. what other types of problems are similar.

then optimize. learn some new techniques, then optimize again.

even though the algorithm sections aren’t explicitly teaching you tried and true algorithms (like what a bubble sort is or implementing a binary search) you should be thinking about the methods you are using to solve these problems. they are algorithms nonetheless.

here is a good video that goes into the difference between an iterative and recursive approach to problem solving, what to consider for each and how to the measure complexity of a given solution. recursion is not always the simpler solution. At least, not until you define what simple is in terms of the problem you are trying to solve.

for reference: the language he is using is Lisp and is a functional programming language

I would say it’s kinda cheating to use flat because flat literally does what you’re trying to do with steamroller, just give it a high enough number of levels to flatten and it’ll pass all the tests. You don’t need to do anything except myArr.flat(someArbitrarilyHighNum). But that’s not really going to teach you anything. It’s really asking you to implement it yourself (which you’re getting close to grasping it seems :+1:)

1 Like

I think that I’m making this a bit more complicated than it needs to be. I’ve been trying to implement a bit of recursion, but I am either (1) not correctly typing my syntax so the language isn’t performative OR (2) I am not performing the JS methods correctly. I’ve gotten negative feedback from reduce() and I feel that there are similar errors throughout the code.
I’ll post it below. Please give me general trajectory errors or syntax errors so that I know which direction to go in editing this.

Thank you!


function firstStage(arr) {
//This is the first level of flattening.  The concat() places the nested arrays into the 1-D array
arr.reduce((a,b)=> {
  a.concat(b)
}, []);
//The next stage is checking to see if an element is actually an array
//Use a for loop to iterate through the initial argument and determine if it is an array and not something besides this
function secondStage(arr){
  for(let i = 0; i < arr.length; i++){
    if(Array.isArray(arr[i])){
      return true
    }
  } return false;
}
//The third stage is creating an empty 1-D array that the results of passing the argument through the previous functions can be emptied into
//The reduced function from the first stage is assigned to the empty 1-D array
//If the boolean logic is true for thisArray - i.e. an element is an array - then the argument for the third stage will be an argument that is emptied into a 1-D array
//If the boolean logic is not true, then the initial function/argument (with the reduce method and boolean method of isArray applied is returned)
let thisArray = [];
function thirdStage(arr){
  thisArray = firstStage(arr);
  if(secondStage(thisArray)){
    thirdStage(thisArray)
  }
  if(!secondStage(thisArray)){
    return thisArray;
  }
}

}

firstStage([1, [2], [3, [[4]]]]);

I’ve attempted to simplify it by just using a method and recursion. I’m not passing any tests and my inclination is that I’m not using recursion correctly. I’m wondering if I’m taking something for granted. My idea is that I should be using forEach on the function again when I reintroduce it as an else statement.

But I also think that this is overkill and I should be introducing something earlier.

I also should note that I’m not entirely sure that isArray declines the nested arrays, but I’ve exhausted all other ideas.

Perhaps I should be using bracket notation to draw them out and assign those that I draw out to variable which I can then push into the empty array? (I already tried something like this in earlier drafts and it didn’t work…but should I revisit it?)

Am I onto something or am I off on a tangent? If it is a tangent, then is there any stage at which I’m on the correct track?

Thank you. Code is below.


function steamrollArray(arr) {
//create empty array for declining array into one dimension
let arrOne = [];
//use forEach to apply method of boolean check on array nature of each element
arr.forEach(function steamrollArray(arr){
//if an element is an array then it will be pushed into the empty array created above
  if(Array.isArray(arr)){
    arrOne.push(arr)
//if an element is not an array then entire process is repeated until true
  } else {
    function steamrollArray(arr)
  }
})
//one dimensional array returned
  return arrOne;
}

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

I received a tip on the type of accumulator I should use and this really helped toward writing the correct code. Yet, I wonder if I understand the logic right. Below I’ve included my answer and with it my explanation of why it works. I want to make sure that I’ve got a proper understanding of what’s going on. Please let me know if I am understanding the answer correctly. Thank you.


function steamrollArray(arr) {
 //the crucial step in this algorithm is including the empty brackets below as the accumulator, which will absorb all other elements into itand thereby become a simple, 1-D array
 //initially, call back on the reduce method which runs a boolean test on the next element to determine if it is an array or not and if so it calls back the function to run the concat() method attaching the argument after whatever is the accumulator and attaching current value to it 
 return arr.reduce((acc, cur)=>{
    if(Array.isArray(cur)){
      return steamrollArray(acc.concat(cur))
    } else {
      //if the value is not an array it will simply concat it to the accumulator and move onto the next value; either way the value is attached to the accumulator which will receive the current value into the 1-D array of which it is accumlating values
     return acc.concat(cur)
    }
  }, [])
  console.log(JSON.stringify(arr))
}

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

With reduce() if you don’t add a starting value for the accumulator, it is set as the element at index 0. In some cases at index 0 you have an other array, so if you don’t have a starting value for the accumulator, that is returned without being flattened

You can read about reduce in great details here: