Basic Algorithm Scripting: Chunky Monkey question

This challenge: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/chunky-monkey

This was someone’s solution which I liked because it seems the most straightforward! However I am just wondering why the final expression is omitted in the for loop and what difference it makes if it is there?

Will it still increment up the array anyway even if the final expression isn’t there?

How does it know to make the second new array start at ‘c’ and not ‘b’? ie. ending up like [“a”, “b”], [“b”, “c”], [“c”, “d”]

function chunkArrayInGroups(arr, size) {

  var newArr = [];
    for (var i = 0; i < arr.length;) 
    newArr.push(arr.splice(i, size));

  return newArr;
}

chunkArrayInGroups(["a", "b", "c", "d"], 2);

You don’t want the return statement inside the loop because function execution ends when a return statement is hit. If that last line was inside the for loop, it would end the loop after pushing only once.

2 Likes

For what its worth, this style isn’t great.

Here is the code with a nicer style. You really want to use a while loop here.
for (let i = 0; i < arr.length;)) is bad form for two reasons:

  1. You want to explicitly include an iteration update (even if there isn’t one)
  2. If you aren’t updating your iterator, then you almost certainly don’t want a for loop

In this code below, the splice actually removes size elements from the array arr, starting at index 0.

// ----------------------------------------------------------
// While loop version
// ----------------------------------------------------------
function chunkArrayInGroups(arr, size) {
  // Start with empty array
  let newArr = [];

  // Splice array into chunks
  while (arr.length) {
    newArr.push(arr.splice(0, size));
  }

  // Return result
  return newArr;
}

// ----------------------------------------------------------
// Output while loop version
// ----------------------------------------------------------
console.log("----- While loop version -----");
console.log("Here we use arr.splice(start, size)");
console.log(chunkArrayInGroups(["a", "b", "c", "d"], 2));

In this example, size = 2. Inside the first while loop iteration, the first two elements, [a, b], are removed. The array arr still has elements, so arr.length is still truthy and we remove the new first two elements [c, d]. Now the array arr is empty and arr.length is falsey, so the loop ends and the new array newArr is returned.

This version of the code is better. You don’t want to change input arrays if you can avoid it.

// ----------------------------------------------------------
// For loop version
// ----------------------------------------------------------
function chunkArrayInGroups(arr, size) {
  // Start with empty array
  let newArr = [];

  // Slice array into chunks
  for (let i = 0; i < arr.length; i += size) {
    newArr.push(arr.slice(i, i + size));
  }

  // Return result
  return newArr;
}

// ----------------------------------------------------------
// Output for loop version
// ----------------------------------------------------------
console.log("----- For loop version -----");
console.log("Here we use arr.slice(start, stop)");
console.log(chunkArrayInGroups(["a", "b", "c", "d"], 2));

In this example, again size = 2. Inside the first for loop iteration, we slice out the elements from 0 to 2, [a, b], and copy them into the new array. We then increment our iterator by size. i is now 2, which is still not past the end of the array, and we slice out the elements from 2 to 4, [c, d], and copy them into the new array. On the next iteration, i is no longer less than the length of the original array, so the loop ends and the new array newArr is returned.

Also, indentation and braces are your friend. They keep your code clearer and better organized.

2 Likes

Thank you so much for your thorough explanation! That helped a lot.
I find that I can’t tell the difference between good form / style and bad form / style … do you have any tips for improving this, or will I just be able to improve gradually through practice and experience?

One question: What is an input array? Could you give an example in the code?

Thank you again.

What Jeremy means by “input array” is the array that your function was passed as an argument. To be more general, when you are iterating over a collection (an array, object, list etc) it is almost never a good idea to be changing that collection. You can do it, if you’re careful, but it is so easy to write infinite loops or to create bugs that are hard to track down.

As Jeremy pointed out, if you do plan on taking the approach of “keep removing parts of the array until it’s gone”, a while loop is a better tool for the job.

2 Likes

Honestly, a big part of how I’ve learned bad vs good style is having people point out how I can code something up better. Just like it took you a while to use English in the ways everyone expects, it’s takes time to learn how to ‘speak’ code.

When I have a function

foo(baz) {
 ... 
  return blarg;
} 

the agrument baz is the input. I tend to say ‘the input array’ and the ‘output array’ when I am dealing with a generic function that takes in an array and outputs an array to help distinguish which one I am referring to.

1 Like

(It’s worth noting that jargon varies depending on your background and community. Jeremy comes from a mathematics background and works mostly in C and Fortran. Every time I change jobs I encounter people who use slightly different terminology and for a while I feel lost even talking about things I actually understand. )
:slight_smile:

1 Like

So did you mean the while loop example you gave is changing the input array by using splice?
When you said ‘This version of the code is better’ - did you mean the while loop or the for loop you wrote underneath it? Sorry I am still confused!

The .splice() version modifies the input array. The correct way to use .splice() is with a while loop rather than a for loop.

But using .slice() and not modifying the input array is more typical. In this case you need to use a for loop.

In order of ‘goodness’ (measured by conforming to conventions/best practices):

  1. .slice() and for (best practice)
  2. .splice() and while
  3. .splice() and for
1 Like

I see! Thanks for clarifying that :slight_smile:

1 Like