3

I am trying to split an array of objects into sets of 3 and there is a slight problem. I run the code and it splits the first group into 2 and the rest into 3. I want the last group to have the remaining elements. So for instance if there are 21 objects then the last group should have 2 but instead the first group is the one with 2. How can I make the last group be the one with the remaining objects?

var newData = [];
var setOfThree = [];

for (i = 0; i < data.length; i++) {
  setOfThree.push(data[i]);

  if (i % 3 == 1) {
    newData.push(setOfThree);
    setOfThree = [];
  }
}

So the data ends up looking like this:

enter image description here

Zach Starnes
  • 3,108
  • 9
  • 39
  • 63

3 Answers3

10

Here's a very clean and efficient solution (leverages the fact that Array.prototype.slice automatically truncates results):

let groupByN = (n, arr) => {
  let result = [];
  for (let i = 0; i < arr.length; i += n) result.push(arr.slice(i, i + n));
  return result;
};

console.log(JSON.stringify(groupByN(3, [])));
console.log(JSON.stringify(groupByN(3, [ 1 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6, 7 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6, 7, 8 ])));
Gershom Maes
  • 7,358
  • 2
  • 35
  • 55
3

The first array gets 2 items because, when i === 1 1%3 will result to 1

Starting from counter 1 could be one solution

    data = [1,2,3,4,5,6,7]
    var newData = [];
    // var setOfThree = []; // not required

    var j = 0
    newData.push([]);
    //pushing at the very begining, this way we won't miss if the data 
    // is not in groups of 3
    for (i = 1; i <= data.length; i++) {
      
      // always updating the final array
      newData[j].push(data[i-1]);

      if (i % 3 == 0) {
        newData.push([]);
        j++;
      }
    }
    if (newData[0].length === 0) {
       // if the data you received was epmty
       newData.pop()
    }
    console.log(newData)
Ashish Ranjan
  • 12,760
  • 5
  • 27
  • 51
2

Here a recursive implementation, with some es6 sugar

var input = [1,2,3,4,5,6,7,8]

function groupByThree([a,b,c,...rest]){
  if (rest.length === 0) return [[a,b,c].filter(x => x!==undefined)]
  return [[a,b,c]].concat(groupByThree(rest))
}

console.log(groupByThree(input))
Francesco
  • 4,052
  • 2
  • 21
  • 29