Home > Software engineering >  Split an array into smaller chunks of arrays with the length provided by size. Need explanation for
Split an array into smaller chunks of arrays with the length provided by size. Need explanation for

Time:07-22

So I was solving this challenge:

Write a function that splits an array (first argument) into groups the length of size (second argument) and returns them as a two-dimensional array.

1. (['a', 'b', 'c', 'd'], 2) is expected to be [['a', 'b'], ['c', 'd']]
2. ([0, 1, 2, 3, 4, 5], 3) is expected to be [[0, 1, 2], [3, 4, 5]]
3. ([0, 1, 2, 3, 4, 5], 2) is expected to be [[0, 1], [2, 3], [4, 5]]
4. ([0, 1, 2, 3, 4, 5], 4) is expected to be [[0, 1, 2, 3], [4, 5]]

I came up with that solution:

function chunkArrayInGroups(arr, size) {
  let result = [];
  for (let i = 0; i < arr.length; i  = size){
    result.push(arr.slice(i, i   size));
  }
  return result;
}

I was also interested in some other possible solution and found that one:

function chunkArrayInGroups(arr, size) {
  let temp = [];
  let result = [];

  for (let a = 0; a < arr.length; a  ) {
    if (a % size !== size - 1) temp.push(arr[a]);
    else {
      temp.push(arr[a]);
      result.push(temp);
      temp = [];
    }
  }

  if (temp.length !== 0) result.push(temp);
  return result;
}

I don't get the point in the IF condition with the remainder. I basically understand how modulo works, but I just don't get it how it would work here for that challenge. Could please someone explain it to me? Thanks!

CodePudding user response:

If the length of the array is not divisible by the size of the group, then add the last group to the result array.

If the length of the array is divisible by the size of the group, then you don't need to add the last group to the result array.

CodePudding user response:

Instead of using your (definitely more efficient, and also clearer) approach of taking consecutive slices, this takes the array item by item, storing the next group to be added in a temporary array. The test is basically asking (with a weird negative test) "Is this index not the last one in the group?" If that condition is true, and we're not on the last one for the current group, we simply add to the temporary group. If it's false, and we are on the last one, we add to the temporary group, add the temporary group to our output and create a new temporary group.

With a little refactoring, we can make this cleaner, perhaps something like this:

function chunkArrayInGroups(arr, size) {
  const result = []
  let temp = []

  for (let a = 0; a < arr .length; a   ) {
    temp .push (arr [a])
    if (a % size === size - 1) {
      result .push (temp)
      temp = []
    }
  }

  if (temp .length > 0) result .push (temp)
  
  return result
}

But this holds no advantages over your approach, and is definitely less efficient. So I wouldn't consider it.

Here's an alternative that is to my mind cleaner, but also less efficient than yours:

const chunk = (xs, n) => xs .length <= n 
  ? [[...xs]] 
  : [xs .slice (0, n)] .concat (chunk (xs .slice (n), n))

This one grabs the first group by slicing it from the beginning of the array, and concatenates the results of recursively calling itself with the remainder of the array. The recursion ends when there are at most n elements remaining, and then we return an array containing only a copy of our input array ([[...x]]). We make the copy because all the other results are copies and not references, and it's better to be consistent.

This is similar to your approach in terms of number of slices and tests, but because of the recursive nature, it will fail for very large arrays and the repeated calls will make it somewhat less efficient. I'm often willing to take that tradeoff for cleaner code, myself, but YMMV.

CodePudding user response:

And maybe you are also interested in another loop based solution:

const a=[...Array(23)].map((_,i)=>i);

function split(a,n){
 return[...Array(Math.ceil(a.length/n))].map((_,i)=>a.slice(i*n,(i 1)*n));
}

for (let n=2;n<13;n  ) // try subdivisions from n=2 to n=13
 console.log(split(a,n));

  • Related