Steamroller Code Review

var arrX = [];

function steamrollArray(arr) {
  // I'm a steamroller, baby
  
  for(var i=0;i<arr.length;i++){
    if(Array.isArray(arr[i]))
      steamrollArray(arr[i]);
    else{
      arrX.push(arr[i]);
    }
  }
  
  return arrX;
}

Hello all,

This is my solution to the steamroller problem, however it doesn’t exactly pass the criteria. Is it because I am returning a global variable?

Thank you

edit: Literally right after I asked this, I looked at past topics and it turns out I should use array.concat. This makes sense because I can now use a local variable instead

My question still remains however, why doesn’t a global variable work?

I think you’re talking about this problem: https://www.freecodecamp.com/challenges/steamroller, am I right? There are some issues with your code.

First: It is not good practice to make your functions depend on global vars. Everything you use in your function should be as much as possible inside the function or another callback function, unless you really want to modify a global var (in which case this var should be put as a parameter to the function). After all, what will happen later on if the global vars are not present or change? Speaking of which:

Second: what will happen if you call this function more than once (that is, if you “reuse” the function again and again)? The next time you call (“use”) the function the var arrX !== [], except if you input as argument NaN, "", etc. This is what I mean:

//call for the first time steamrollArray, arrX = []
steamrollArray([1,[[2]],3]); 
//outputs (as expected): [1,2,3]

//call second time steamrollArray, now arrX = [1,2,3]
steamrollArray([4,[5,[6]]]);
//outputs (not as expected): [1,2,3,4,5,6]

Third: Don’t be afraid of creating more than one function and using more than one as needed. In the “steamroll” problem from FreeCodeCamp, you can only call one function, so var x = 'foo'; func1(x); func2(x); is not allowed, you have to wrap everything up in only one function. For this, you can do a callback to another function*, this will rid you of the necessity of having a global var when doing recursion (only take care not to fall into the “callback hell” by doing too many callbacks). Like this (in pseudo code):

*I hope I’m right, but for me a callback function is any function you “call back”, that is, that you call from another function (specially as an argument).

function func1(arg, callbackfunction=func2) {
  //change arg to what you want
  arg+= " ";
  return callbackfunction(arg);
}
  
function func2(arg){
  var someVar = 'bar';
  //do some recursion, now someVar will be === 'bar' every time the recursion occurs, but your 'arg' will be different
  arg+= someVar;
  if (arg.length <= 100) return func2(arg); else return arg; //you can also write this with a ternary operator, like this: return (arg.length <= 100) ? func2(arg) : arg; //this means in english: return a value ---> but is arg.length <= 100? if 'yes', return func2(arg), if 'no', return arg
  someVar = "not 'bar' anymore";
}

func1('foo',func2); //this is basically the same as executing:  var x = 'foo'; x = func1(x); x = func2(x);

/*this is a bad example, obviously a while loop would be better
but it is meant only as a (bad) example of a callback function*/

But for your problem specifically, it’s easier to provide a second optional argument, like this:

function steamrollArray(arr, arrX=[]) {    //note the new 'arrX=[]' parameter
  // I'm a steamroller, baby
  for(var i=0;i<arr.length;i++){
    if(Array.isArray(arr[i])) {
      steamrollArray(arr[i],arrX);      //note the arrX array being passed on recursively as argument again (as the second parameter of the function steamrollArray)
    } else {
      arrX.push(arr[i]);
    }
  }
  return arrX;  
}

Having said this, you did a great job, but only forgot that the global var arrX wouldn’t remain = [] . I used to make such mistakes a lot, but by doing mistakes you learn to watch out for them. BTW, I’m rather a newbie myself so I hope I haven’t made any mistakes.

Keep up the good work!

2 Likes

wow thanks for the writeup, appreciate it!

You’re most welcome!:wink: Sorry if it’s a bit too long. Another way you could implement your function with a global var would be just before the return arrX; in your code, you could write instead:

var arr2 = arrX;
arrX = [];    //this flushes the global scoped arrX
return arr2;

But I’d advise against depending on global vars for functions, like I said. Suppose you copy your function code to another script you have, won’t you have to find all the global vars to copy them along? It has difficult portability also if you move it forward or backwards in a long script, since the global vars might have changed. Except for this difficulty, the rest of your logic was spot on.

I am grateful for you

What about if you only use the reduce method

I found really easy the following method...

I found a lot of helpful information on this webpage:

reduce method

function steamrollArray(arr) {
 

let i = 0
do{ arr= arr.reduce((acc, val) => acc.concat(val), []);
}while (i<arr.length)

return arr

}


1 Like