3

I have an array

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; 

I want to group it into a set of n arrays such that first n elements in result[0] next n elements in result[1] and if any element is remaining it is discarded.

let sampleOutput = [[0, 1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13]] for n = 7; 

Here is my code:

function group5(arr, len) {
 let result = [];
 let loop=parseInt(arr.length/len)
 for (let i=0; i<arr.length; i+=len) {
  let x = []; let limitReached = false;
  for (let j=0; j<len; j++) {
   if (arr[i+j]) {
    x.push(arr[i+j]);
   } else {
    limitReached = true;
    break;
   }
  }
 if (!limitReached) {
  result.push(x);
 } else {
  break;
  }
 }
 return result;
}

But I am unable to get expected result. I have tried following things.

  1. Map function
  2. Running i loop to arr.len
  3. Checking arr.len % 7
  4. Creating an array for every third element.
  5. This question is not duplicate of Split array into chunks because I have to discard extra elements that can not be grouped into sets of n.
  6. I have to keep the original array Immutable because I am using this on props in a child component. I need a function that does not modify the original array.
Vishu Bhardwaj
  • 271
  • 4
  • 12
  • 3
    Possible duplicate of [Split array into chunks](https://stackoverflow.com/questions/8495687/split-array-into-chunks) – Andreas Aug 22 '18 at 14:01
  • Hello, thanks everyone. I settled for following solution. Consider this question closed. export function groupInChunks (arr, len) { let chunks = []; let i = 0; while((arr.length - i) >= len) { chunks.push(arr.slice(i, len + i)); i+=len; } return chunks; } – Vishu Bhardwaj Sep 21 '18 at 04:39

6 Answers6

4

It's pretty straigthforward using Array.from

const list = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14];

function chunkMaxLength(arr, chunkSize, maxLength) {
  return Array.from({length: maxLength}, () => arr.splice(0,chunkSize));
}

console.log(chunkMaxLength(list, 7, 2));
baao
  • 71,625
  • 17
  • 143
  • 203
  • Which is why it is mentioned in [one of the answers](https://stackoverflow.com/a/10456644/402037) from the duplicate. – Andreas Aug 22 '18 at 14:18
  • Yeah, if you compare the answers carefully, you'll find the differences. @Andreas This answer is, in contrary to the other answer, doing what OP is asking for, and it's more performant than the Array.from approach in the other answer. – baao Aug 22 '18 at 14:24
2

What about :

function group5(arr, len) {
     let chunks = [];
     let copy   = arr.splice(); // Use a copy to not modifiy the original array
     while(copy.length > len) {
         chunks.push(copy.splice(0, len));
     }
     return chunks;
}
Grégory
  • 338
  • 2
  • 10
  • It is not discarding extra elements that can not be grouped into sets of 7. Yours answer results in [[0..6], [7..13], [14]] I don't want elements whose set can not be made of 7 elements. – Vishu Bhardwaj Aug 22 '18 at 14:11
  • I updated my answer, it's now returning the expected result. – Grégory Aug 22 '18 at 14:12
  • Hi, This solution is quiet correct, What can I do to not modify the original array. The original array comes from props (react-native), hence I can't modify that. – Vishu Bhardwaj Aug 23 '18 at 04:51
  • I updated my answer again in order to not modify the original array. :) – Grégory Aug 23 '18 at 10:03
1

I usually prefer declarative solutions (map, reduce, etc), but in this case I think a for is more understandable:

function groupArray(array, num) {
  const group = [];

  for (let i = 0; i < array.length; i += num) {
    group.push(array.slice(i, i + num));
  }

  return group;
}
Aral Roca
  • 5,442
  • 8
  • 47
  • 78
0

You could use a combination of reduce and filter to achieve the expected result. This example gives you a third control over length which makes the code a bit more reuseable.

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; 
const groupNumber = 7;
const groupCount = 2;


const groupArray = (group, size, length) => group.reduce((accumulator, current, index, original) =>   
  ((index % size) == 0)
    ? accumulator.concat([original.slice(index, index + size)])
    : accumulator, []
  ).filter((single, index) => index < length)

const test = groupArray(arr, groupNumber, groupCount);
console.log(test);

Step by Step

const groupArray = (group, size, length) => {
  // if (index modulus size) equals 0 then concat a group of 
  // length 'size' as a new entry to the accumulator array and 
  // return it, else return the accumulator
  const reducerFunc = (accumulator, current, index, original) =>   
  ((index % size) == 0)
    ? accumulator.concat([original.slice(index, index + size)])
    : accumulator

  // if the current index is greater than the supplied length filter it out
  const filterFunc = (single, index) => index < length;

  // reduce and filter original group
  const result = group.reduce(reducerFunc, []).filter(filterFunc)

  return result;
}
D Lowther
  • 1,609
  • 1
  • 9
  • 16
0

Also (apart from the existing approaches) you can have a recursive approach like this

function chunks(a, size, r = [], i = 0) {
    let e = i + size;
    return e <= a.length ? chunks(a, size, [...r, a.slice(i, e)], e) : r;
}

function chunks(a, size, r = [], i = 0) {
    let e = i + size;
 return e <= a.length ? chunks(a, size, [...r, a.slice(i, e)], e) : r;
}

var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];


console.log('Chunk with 3: ', chunks(arr, 3));
console.log('Chunk with 4: ', chunks(arr, 4));
console.log('Chunk with 5: ', chunks(arr, 5));
console.log('Chunk with 6: ', chunks(arr, 6));
console.log('Chunk with 7: ', chunks(arr, 7));
Koushik Chatterjee
  • 4,106
  • 3
  • 18
  • 32
0

I able to solve the problem with this code

function groupN(n, arr) {
  const res = [];
  let limit = 0;
  while (limit+n <= arr.length) {
    res.push(arr.slice(limit, n + limit));
    limit += n
  }
  return res
}
principiorum
  • 528
  • 7
  • 21