Can anyone please explain to me in simple words the meaning of this code

function steamrollArray(arr) {
  var flattenedArray = [];

  var flatten = function(arg) {
    if (!Array.isArray(arg)) {
      flattenedArray.push(arg);
    } else {
      for (var a in arg) {
        flatten(arg[a]);
      }
    }
  };

  arr.forEach(flatten);
  return flattenedArray;
}
function steamrollArray(arr) {
  var flattenedArray = [];  // creates an empty array

  var flatten = function(arg) {
     // first check if the item is NOT an array, because if it is an array
    // we will need to flatten the sub-arrays
    if (!Array.isArray(arg)) {
      // if the item is NOT an array (i.e., is an entry), then we push it on the empty array
      flattenedArray.push(arg);
    } else {
       //otherwise we repeat the process, one layer down
       // i.e., we flatten the subarray
       // or, if the subarray is an array, we will wind up back here
      for (var a in arg) {
        flatten(arg[a]);
      }
    }
  };

  arr.forEach(flatten);  //runs the "flatten" function on each item in the array
  return flattenedArray;   //returns the flattened array
}
2 Likes

Thanks but what I meant was the functioning of this code, its recursion logic in simple words.

I’m not sure what exactly you’re asking, but It’s flattening an array, regardless of how many subarrays there are. Hence, every time we encounter an array we enter the recursion.

Try tracing what it does to:
[0,1,[2,3],4,[5,[6,7],8],9] for an example. If you want you can add a few console.logs like so:

  var flatten = function(arg) {
    console.log("starting flatten for "+arg);
    if (!Array.isArray(arg)) {
     console.log(arg+" was not an array, pushing");
      flattenedArray.push(arg);
    } else {
     console.log(arg+" was an array, in else loop")
      for (var a in arg) {
       console.log("in else loop, gonna flatten "+arg[a])
        flatten(arg[a]);
      }
    }

The key is really the else / for loop that ensures every entry of the array goes through flatten, which means recursively that every sub-entry of the array (and so on down) will also.

This code has one problem:

Here you iterate through every item in the array:

Here you do absolutely the same, but in a weird and possibly problematic way:

As a note, I’m not really a big fan of these quasi-recursive solutions where you write a helper function inside of your function to bypass using recursive logic.

  1. The result of your function is the same if you use:
    arr.flat()
  2. Your code in simple words:
    Exmaple:
    arr = [5, [2, 3], [7, 1 , 4], 8]

a) 5 is no array => push it directly in flattenArray.
flattenArray = [5]
b) [2, 3] is an array:
Now you take every element of that array and apply your function “flatten” on it:
*) flattenArray = [5, 2]
**) flattenArray = [5, 2, 3]

Do the same with the other elements of arr.

The end result will be [5, 2, 3, 7, 1, 4, 8]

Any object-like structure that has structures of same kind as its children can be traversed (and usually is) using recursive function, because what applies to parent (in your case - array) same applies to children of the same type, therefore parent function can be reused on children.

So recursion here is a way to get to all elements of parent and all the elements of children, if they are of the same type and push all those elements to flattenedArray

Internal recursive function here is caused by using .push() and can be omitted once for all by using .concat() instead:

let arr = [];
arr.push([1]); // [[1]] :(
arr = arr. concat([1]); // [1] :)

I was more commenting on the use of an ‘internal global variable’. It’s the sort of solution I see when someone tries to use a global variable as part of the recursion instead of using the return value of the function call, gets yelled at for making a fragile solution that pollutes the global space, and wraps their solution in an outer function instead rewriting the function to use the return value.

You should be able to use recursive calls to steamroll with push or concat internally. (or shift if you’re feeling spicy)

Well, .forEach() function he uses has such nature, what can you do? It would be pointless otherwise :slight_smile:

Sure, I get it flows from the solution he found/wrote, I just find it awkward to write quasi-recursive code. It’s verbose and just… weird

Hello, It was the solution given on FreeCodeCamp. I was myself confused about how did this even work so I asked it here. Please update it if it is not appropriate.

Hello, this was the solution give on FreeCodeCamp. Please update it if it has any problem.

It works fine as a solution… It’s just not the way I would have done it. Verbose and awkward to Jeremy does not mean the solution is wrong, just that I’ll complain if I see it in a code review.

I was not supposed to use arr.flat()

If you have time… what would be the way you would have done it ?

Sure. Similar idea, but using true recursion. I’m surprised that the guide doesn’t include this sort of solution.

function hulkSmash(myArr) {
  if (!Array.isArray(myArray)) {
    // Base case
    // We have a single element, just return it
    return [myArr];
 } else {
    // Recursive case
    let smashArr = [];
    for (let i = 0; i < myArr.length; i++) {
      smashArr.push(...hulkSmash(myArr[i]));
    } 
    return smashArr;
  }
}

It could be tightened up, but its late at night so I won’t refactor right now.