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
  • 261
  • 3
  • 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

5 Answers5

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
  • 9
  • 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
2

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
  • 67,185
  • 15
  • 124
  • 181
  • 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
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,569
  • 1
  • 7
  • 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
  • 3,938
  • 3
  • 16
  • 31
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
}
muhsalaa
  • 419
  • 5
  • 18