1076

Let's say that I have an Javascript array looking as following:

["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.

What approach would be appropriate to chunk (split) the array into many smaller arrays with, lets say, 10 elements at its most?

6

88 Answers 88

1395

The array.slice() method can extract a slice from the beginning, middle, or end of an array for whatever purposes you require, without changing the original array.

const chunkSize = 10;
for (let i = 0; i < array.length; i += chunkSize) {
    const chunk = array.slice(i, i + chunkSize);
    // do whatever
}

The last chunk may be smaller than chunkSize. For example when given an array of 12 elements the first chunk will have 10 elements, the second chunk only has 2.

Note that a chunkSize of 0 will cause an infinite loop.

Sign up to request clarification or add additional context in comments.

19 Comments

Remember if this is a util function to assert against chunk being 0. (infinite loop)
Nope, the last chunk should just be smaller than the others.
@Blazemonger, indeed! Next time I will actually try it myself before jumping to conclusions. I assumed (incorrectly) that passing an input into array.slice that exceeded the bounds of the array would be a problem, but it works just perfect!
For one-liners (chain-lovers): const array_chunks = (array, chunk_size) => Array(Math.ceil(array.length / chunk_size)).fill().map((_, index) => index * chunk_size).map(begin => array.slice(begin, begin + chunk_size));.
Why do you need j? First I thought it is an optimisation, but it is actually slower than for(i=0;i<array.length;i++){}
|
322

Here's a ES6 version using reduce

const perChunk = 2 // items per chunk    

const inputArray = ['a','b','c','d','e']

const result = inputArray.reduce((resultArray, item, index) => { 
  const chunkIndex = Math.floor(index/perChunk)

  if(!resultArray[chunkIndex]) {
    resultArray[chunkIndex] = [] // start a new chunk
  }

  resultArray[chunkIndex].push(item)

  return resultArray
}, [])

console.log(result); // result: [['a','b'], ['c','d'], ['e']]

And you're ready to chain further map/reduce transformations. Your input array is left intact


If you prefer a shorter but less readable version, you can sprinkle some concat into the mix for the same end result:

inputArray.reduce((all,one,i) => {
   const ch = Math.floor(i/perChunk); 
   all[ch] = [].concat((all[ch]||[]),one); 
   return all
}, [])

You can use remainder operator to put consecutive items into different chunks:

const ch = (i % perChunk); 

10 Comments

This seems like the most condensed solution. What is chunkIndex = Math.floor(index/perChunk) getting ? Is it the average ?
5/2 = 2.5 and Math.floor(2.5) = 2 so item with index 5 will placed in bucket 2
I like your use of all and one here - makes reduce easier to read to my brain than other examples I've seen & used.
Hot take from someone who loves functional programming, a for loop is more readable than reducing into a new array
Reading solutions like this I really wonder if people ever consider the space/time complexity of their algorithms anymore. concat() clones arrays, which means that not only does this algorithm iterate every element as @JPdelaTorre notices but it does so per every other element. With one million items (which is really not that weird for any real use-case) this algorithm takes nearly 22 seconds to run on my PC, while the accepted answer takes 8 milliseconds. Go team FP!
|
207

Using generators

function* chunks(arr, n) {
  for (let i = 0; i < arr.length; i += n) {
    yield arr.slice(i, i + n);
  }
}

let someArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log([...chunks(someArray, 2)]) // [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

Can be typed with Typescript like so:

function* chunks<T>(arr: T[], n: number): Generator<T[], void> {
  for (let i = 0; i < arr.length; i += n) {
    yield arr.slice(i, i + n);
  }
}

2 Comments

function* chunks<T>(arr: T[], n: number): Generator<T[], void> { and then use const foo = [ ...chunks( bar, 4 ) ]; - @RayFoss
173

Modified from an answer by dbaseman: https://stackoverflow.com/a/10456344/711085

Object.defineProperty(Array.prototype, 'chunk_inefficient', {
  value: function(chunkSize) {
    var array = this;
    return [].concat.apply([],
      array.map(function(elem, i) {
        return i % chunkSize ? [] : [array.slice(i, i + chunkSize)];
      })
    );
  }
});

console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk_inefficient(3)
)
// [[1, 2, 3], [4, 5, 6], [7]]


minor addendum:

I should point out that the above is a not-that-elegant (in my mind) workaround to use Array.map. It basically does the following, where ~ is concatenation:

[[1,2,3]]~[]~[]~[] ~ [[4,5,6]]~[]~[]~[] ~ [[7]]

It has the same asymptotic running time as the method below, but perhaps a worse constant factor due to building empty lists. One could rewrite this as follows (mostly the same as Blazemonger's method, which is why I did not originally submit this answer):

More efficient method:

// refresh page if experimenting and you already defined Array.prototype.chunk

Object.defineProperty(Array.prototype, 'chunk', {
  value: function(chunkSize) {
    var R = [];
    for (var i = 0; i < this.length; i += chunkSize)
      R.push(this.slice(i, i + chunkSize));
    return R;
  }
});

console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk(3)
)


My preferred way nowadays is the above, or one of the following:

Array.range = function(n) {
  // Array.range(5) --> [0,1,2,3,4]
  return Array.apply(null,Array(n)).map((x,i) => i)
};

Object.defineProperty(Array.prototype, 'chunk', {
  value: function(n) {

    // ACTUAL CODE FOR CHUNKING ARRAY:
    return Array.range(Math.ceil(this.length/n)).map((x,i) => this.slice(i*n,i*n+n));

  }
});

Demo:

> JSON.stringify( Array.range(10).chunk(3) );
[[1,2,3],[4,5,6],[7,8,9],[10]]

Or if you don't want an Array.range function, it's actually just a one-liner (excluding the fluff):

var ceil = Math.ceil;

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array(ceil(this.length/n)).fill().map((_,i) => this.slice(i*n,i*n+n));
}});

or

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array.from(Array(ceil(this.length/n)), (_,i)=>this.slice(i*n,i*n+n));
}});

"Don't modify Object.prototype" --some comments

Of course that's fine, you can put the above in your own function chunk(arr, chunkSize); how you package your chunk function is immaterial to answering OP's question (how to code such a function).

However I will mildly double-down on the 'wrong' act of extending Array.prototype, and here's the justification: This isn't some horrible thing. The link shared in the comments does a good job explaining the potential pitfalls, but people may read the link and see "extending prototype bad!" and not understand the nuance. Many languages have such functionality, and the semantics are basically managed by the programmer (at import/etc. time):

  1. Perhaps don't extend prototype if you're writing a library! Libraries should play nice by not polluting the global namespace. Or if you do so, make it quite clear to users that it may interact poorly with other libraries that do this, or your own code. You can define myLib.chunk = function() {...} or module-export it or whatnot, or use Object.defineProperty('myLib_chunk', ...
  2. You can use a prefix (defineProperty('myLib_chunk', ...) if you aren't going to do this often. But, if you are going to be chunking your arrays everywhere in your code, go ahead and extend prototype! Especially if your code will only be used in a small downstream (non-library) project. This is just the age-old debate of "why is from LIBRARY import *" [e.g. in Python] bad? Well it's clearly bad if you overuse it, and it's sometimes good (who wants to write Math.floor everywhere in your javascript code?! Math functions are not usually implementation-dependent!). In general, you should namespace everything myLib.yourExports, but not necessarily to the extent of readability.
  3. Obviously don't make make it enumerable (which would break for...in)... using Object.defineProperty will make it non-enumerable by default.
  4. If ECMAScript decides to ship a .chunk, they should have reserved it or built better functionality sooner. New ECMAScript standards always have the risk of breaking existing code. If you want to future-proof your code because you won't be maintaining it or don't want to (an extremely important consideration!), don't code using this method, and don't add variables to the global namespace either (without some extensive future-proofing, maybe like Symbol, or prefixing).

So... thank you to the commenters for pointing out this consideration. This discussion is outside the scope of this answer because really it could be had with any answer on StackOverflow, but that's my take.

9 Comments

Eh, I'd avoid messing with the prototype as the feeling of coolness you get from calling the chunk function on the array doesn't really outweigh the extra complexity you're adding and the subtle bugs that messing with built-in prototypes can cause.
He's not messing with them he's extending them for Arrays. I understand never touching Object.prototype because that would bubble to all objects (everything) but for this Array specific function I don't see any issues.
Based on the compatibility chart on the mozilla dev site, Array.map for for IE9+. Be careful.
@rlemon Here you go, here’s the issues this causes. Please NEVER modify native prototypes, especially without vendor prefix: developers.google.com/web/updates/2018/03/smooshgate It’s fine if you add array.myCompanyFlatten, but please don’t add array.flatten and pray that it’ll never cause issues. As you can see, mootools’ decision years ago now influences TC39 standards.
@rlemon It's still dangerous because it may clash with what someone else has done, or with a future method. To be safe, just create a method that takes the array and avoid problems altogether. humanwhocodes.com/blog/2010/03/02/…
|
150

Try to avoid mucking with native prototypes, including Array.prototype, if you don't know who will be consuming your code (3rd parties, coworkers, yourself at a later date, etc.).

There are ways to safely extend prototypes (but not in all browsers) and there are ways to safely consume objects created from extended prototypes, but a better rule of thumb is to follow the Principle of Least Surprise and avoid these practices altogether.

If you have some time, watch Andrew Dupont's JSConf 2011 talk, "Everything is Permitted: Extending Built-ins", for a good discussion about this topic.

But back to the question, while the solutions above will work, they are overly complex and requiring unnecessary computational overhead. Here is my solution:

function chunk (arr, len) {

  var chunks = [],
      i = 0,
      n = arr.length;

  while (i < n) {
    chunks.push(arr.slice(i, i += len));
  }

  return chunks;
}

// Optionally, you can do the following to avoid cluttering the global namespace:
Array.chunk = chunk;

7 Comments

"avoid mucking with native prototypes" new js developers should get a temporary, if not permanent, tattoo of this phrase.
I've been using javascript for years and spend next to no time bothering with prototype, at the very most calling functions, never modifying like you see some people do.
the best suggestion in my eyes, the simplest to understand and in implementation, thank you very much!
@JacobDalton I think it's all universities' fault. People think OOP must be used everywhere. So they are scared of "just creating a function". They want to be sure to put it inside something. Even if it's not appropriate at all. If there is no dot notation, there is no "architecture".
@Gherman I see this a lot too. I work in Laravel mostly and folks in my shop tend to create all sorts of manager classes in order to "stick to" OOP, but in doing so break the conventions of Laravel making coming into a project that much more complicated.
|
105

Splice version using ES6

let  [list,chunkSize] = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6];
list = [...Array(Math.ceil(list.length / chunkSize))].map(_ => list.splice(0,chunkSize))
console.log(list);

7 Comments

it modifies the original list array
Easy fix using .slice().. .map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
On JSPerf this is drastically more performant than many of the other answers.
It's better to use [ ] instead of new Array(): [...Array(Math.ceil(list.length / chuckSize)].map(_ => list.splice(0,chuckSize))
If you're chunking for presentation purposes, you will most likely want to avoid in-place mutation of the original model - here's a variation as a pure function using slice instead of splice: const chunk = (list, size) => [...Array(Math.ceil(list.length / size))].map((_, i) => list.slice(i * size, i * size + size))
|
94

I tested the different answers into jsperf.com. The result is available there: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds

And the fastest function (and that works from IE8) is this one:

function chunk(arr, chunkSize) {
  if (chunkSize <= 0) throw "Invalid chunk size";
  var R = [];
  for (var i=0,len=arr.length; i<len; i+=chunkSize)
    R.push(arr.slice(i,i+chunkSize));
  return R;
}

5 Comments

Thanks @AymKdn for making this benchmark: This was so helpful! I was using the splice approach and it crashed my Chrome v70 browser at a chunk size of 884432. With your suggested "slice" approach in place, my code doesn't crash the "render" process of the browser anymore. :)
Here's a typescript version of this: function chunk<T>(array: T[], chunkSize: number): T[][] { const R = []; for (let i = 0, len = array.length; i < len; i += chunkSize) R.push(array.slice(i, i + chunkSize)); return R; }
How long does it take for chunkSize = 0? Some valid function input should not stop the process.
@ceving I've just added a condition when chunkSize is <= 0
@AymKdn I am not sure, if returning the array unmodified is the best error handling.The expected return type of the function is Array<Array>. And a non-positive chunk size does not make any sense. So throwing an error seems reasonable for me.
47

I'd prefer to use splice method:

var chunks = function(array, size) {
  var results = [];
  while (array.length) {
    results.push(array.splice(0, size));
  }
  return results;
};

7 Comments

Must be careful with this splice solution since it modifies the original array, so be sure to clearly document the side effects.
Then use slice instead
@mplungjan The result would be the same array over and over again when using slice. So it's not really a drop-in replacement without some more modifications.
The only thing that I would add to this answer is a clone to the original array. I would do that with ES6's spread operator. var clone = [...array] then do the lenght checking and splicing over that cloned array.
Or if you can't use ES6 features you can simply array = array.slice() which also creates a shallow copy.
|
47

Nowadays you can use lodash' chunk function to split the array into smaller arrays https://lodash.com/docs#chunk No need to fiddle with the loops anymore!

2 Comments

I feel like there should be disclaimer to SO javascript questions: have you tried lodash? Pretty much the first thing I include in node or the browser.
Not everyone want/can include 3rd party libraries
39

Old question: New answer! I actually was working with an answer from this question and had a friend improve on it! So here it is:

Array.prototype.chunk = function ( n ) {
    if ( !this.length ) {
        return [];
    }
    return [ this.slice( 0, n ) ].concat( this.slice(n).chunk(n) );
};

[1,2,3,4,5,6,7,8,9,0].chunk(3);
> [[1,2,3],[4,5,6],[7,8,9],[0]]

3 Comments

fyi, the performance of this method is O(N^2), so it should not be used in performance-critical sections of code, or with long arrays (specifically, when the array's .length is much greater than the chunk-size n). If this was a lazy language (unlike javascript), this algorithm would not suffer from O(N^2) time. That said, the recursive implementation is elegant. You can probably modify it to improve performance by first defining a helper function that recurses on array,position, then dispatching: Array.prototype.chunk returns [your helper function](...)
thanks sensai for blessing me with your spirit that i must have chanelled tonight
or... var chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
32

One more solution using Array.prototype.reduce():

const chunk = (array, size) =>
  array.reduce((acc, _, i) => {
    if (i % size === 0) acc.push(array.slice(i, i + size))
    return acc
  }, [])

// Usage:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const chunked = chunk(numbers, 3)
console.log(chunked)

This solution is very similar to the solution by Steve Holgado. However, because this solution doesn't utilize array spreading and doesn't create new arrays in the reducer function, it's faster (see jsPerf test) and subjectively more readable (simpler syntax) than the other solution.

At every nth iteration (where n = size; starting at the first iteration), the accumulator array (acc) is appended with a chunk of the array (array.slice(i, i + size)) and then returned. At other iterations, the accumulator array is returned as-is.

If size is zero, the method returns an empty array. If size is negative, the method returns broken results. So, if needed in your case, you may want to do something about negative or non-positive size values.


If speed is important in your case, a simple for loop would be faster than using reduce() (see the jsPerf test), and some may find this style more readable as well:

function chunk(array, size) {
  // This prevents infinite loops
  if (size < 1) throw new Error('Size must be positive')

  const result = []
  for (let i = 0; i < array.length; i += size) {
    result.push(array.slice(i, i + size))
  }
  return result
}

1 Comment

your reduce example is by far the cleanest way of doing it
31

ONE-LINER

const chunk = (a,n)=>[...Array(Math.ceil(a.length/n))].map((_,i)=>a.slice(n*i,n+n*i));

For TypeScript

const chunk = <T>(arr: T[], size: number): T[][] =>
  [...Array(Math.ceil(arr.length / size))].map((_, i) =>
    arr.slice(size * i, size + size * i)
  );

DEMO

const chunk = (a,n)=>[...Array(Math.ceil(a.length/n))].map((_,i)=>a.slice(n*i,n+n*i));
document.write(JSON.stringify(chunk([1, 2, 3, 4], 2)));

Chunk By Number Of Groups

const part=(a,n)=>[...Array(n)].map((_,i)=>a.slice(i*Math.ceil(a.length/n),(i+1)*Math.ceil(a.length/n)));

For TypeScript

const partitionArray = <T>(array: T[], parts: number): T[][] => {
  const itemsPerPart = Math.ceil(array.length / parts);
  return [...Array(parts)].map((_, index) =>
    array.slice(index * itemsPerPart, (index + 1) * itemsPerPart)
  );
};

DEMO

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

document.write(JSON.stringify(part([1, 2, 3, 4, 5, 6], 2))+'<br/>');
document.write(JSON.stringify(part([1, 2, 3, 4, 5, 6, 7], 2)));

5 Comments

chunk([1,2,3,4],2) yields [ [ 1, 2 ], [ 3, 4 ], [] ]. Doesn't seem right to me.
Can't reproduce your results @HansBouwmeeste. u.davwheat.dev/3Om2Au5D.png
it was, but fixed now, my bad i should mention
@David Wheatley. Confirmed. I tried the latest version and it works good now.
You should prefer the answer provided by @Benny Neugebauer though, for it does not create any intermediate array. This example here is actually creating two extra arrays. First is Array(n), second is due to [... ] wrapping the first one. The resulting array is neither of the two for map() is creating a third one. You could get rid of one array by using Array(n).fill(0) instead of [...Array(n)].
28

There have been many answers but this is what I use:

const chunk = (arr, size) =>
  arr
    .reduce((acc, _, i) =>
      (i % size)
        ? acc
        : [...acc, arr.slice(i, i + size)]
    , [])

// USAGE
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
chunk(numbers, 3)

// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

First, check for a remainder when dividing the index by the chunk size.

If there is a remainder then just return the accumulator array.

If there is no remainder then the index is divisible by the chunk size, so take a slice from the original array (starting at the current index) and add it to the accumulator array.

So, the returned accumulator array for each iteration of reduce looks something like this:

// 0: [[1, 2, 3]]
// 1: [[1, 2, 3]]
// 2: [[1, 2, 3]]
// 3: [[1, 2, 3], [4, 5, 6]]
// 4: [[1, 2, 3], [4, 5, 6]]
// 5: [[1, 2, 3], [4, 5, 6]]
// 6: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 7: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 8: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 9: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

1 Comment

Nice solution and nice visual representation of the iterations. I ended up with a very similar solution which I posted as an answer: stackoverflow.com/a/60779547
25

I think this a nice recursive solution with ES6 syntax:

const chunk = function(array, size) {
  if (!array.length) {
    return [];
  }
  const head = array.slice(0, size);
  const tail = array.slice(size);

  return [head, ...chunk(tail, size)];
};

console.log(chunk([1,2,3], 2));

Comments

19

Ok, let's start with a fairly tight one:

function chunk(arr, n) {
    return arr.slice(0,(arr.length+n-1)/n|0).
           map(function(c,i) { return arr.slice(n*i,n*i+n); });
}

Which is used like this:

chunk([1,2,3,4,5,6,7], 2);

Then we have this tight reducer function:

function chunker(p, c, i) {
    (p[i/this|0] = p[i/this|0] || []).push(c);
    return p;
}

Which is used like this:

[1,2,3,4,5,6,7].reduce(chunker.bind(3),[]);

Since a kitten dies when we bind this to a number, we can do manual currying like this instead:

// Fluent alternative API without prototype hacks.
function chunker(n) {
   return function(p, c, i) {
       (p[i/n|0] = p[i/n|0] || []).push(c);
       return p;
   };
}

Which is used like this:

[1,2,3,4,5,6,7].reduce(chunker(3),[]);

Then the still pretty tight function which does it all in one go:

function chunk(arr, n) {
    return arr.reduce(function(p, cur, i) {
        (p[i/n|0] = p[i/n|0] || []).push(cur);
        return p;
    },[]);
}

chunk([1,2,3,4,5,6,7], 3);

4 Comments

Doesnt Works in iE8.
HA! i love the kitten comment. sorry for no additional constructive input :)
I would do (p[i/n|0] || (p[i/n|0] = [])), so you don't assign a value, if not necessary...
for Currying (partial applying applied functions) you need in bind thisArg = null in your example chunker.bind(null, 3) docs Function.prototype.bind()
14

I aimed at creating a simple non-mutating solution in pure ES6. Peculiarities in javascript make it necessary to fill the empty array before mapping :-(

function chunk(a, l) { 
    return new Array(Math.ceil(a.length / l)).fill(0)
        .map((_, n) => a.slice(n*l, n*l + l)); 
}

This version with recursion seem simpler and more compelling:

function chunk(a, l) { 
    if (a.length == 0) return []; 
    else return [a.slice(0, l)].concat(chunk(a.slice(l), l)); 
}

The ridiculously weak array functions of ES6 makes for good puzzles :-)

1 Comment

I also wrote mine much like this. It still works if you remove the 0 from the fill, which makes the fill look a little more sensible, imho.
12

Created a npm package for this https://www.npmjs.com/package/array.chunk

var result = [];

for (var i = 0; i < arr.length; i += size) {
  result.push(arr.slice(i, size + i));
}
return result;

When using a TypedArray

var result = [];

for (var i = 0; i < arr.length; i += size) {
  result.push(arr.subarray(i, size + i));
}
return result;

1 Comment

@A1rPun My bad, I didn't add comment there. Yea, there is no slice method for TypedArray, we can use subarray instead developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
11

I recommend using lodash. Chunking is one of many useful functions there. Instructions:

npm i --save lodash

Include in your project:

import * as _ from 'lodash';

Usage:

const arrayOfElements = ["Element 1","Element 2","Element 3", "Element 4", "Element 5","Element 6","Element 7","Element 8","Element 9","Element 10","Element 11","Element 12"]
const chunkedElements = _.chunk(arrayOfElements, 10)

You can find my sample here: https://playcode.io/659171/

Comments

10

The following ES2015 approach works without having to define a function and directly on anonymous arrays (example with chunk size 2):

[11,22,33,44,55].map((_, i, all) => all.slice(2*i, 2*i+2)).filter(x=>x.length)

If you want to define a function for this, you could do it as follows (improving on K._'s comment on Blazemonger's answer):

const array_chunks = (array, chunk_size) => array
    .map((_, i, all) => all.slice(i*chunk_size, (i+1)*chunk_size))
    .filter(x => x.length)

1 Comment

- short and nice
10

Using Array.prototype.splice() and splice it until the array has element.

Array.prototype.chunk = function(size) {
    let result = [];
    
    while(this.length) {
        result.push(this.splice(0, size));
    }
        
    return result;
}

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr.chunk(2));

Update

Array.prototype.splice() populates the original array and after performing the chunk() the original array (arr) becomes [].

So if you want to keep the original array untouched, then copy and keep the arr data into another array and do the same thing.

Array.prototype.chunk = function(size) {
  let data = [...this];  
  let result = [];
    
    while(data.length) {
        result.push(data.splice(0, size));
    }

    return result;
}

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log('chunked:', arr.chunk(2));
console.log('original', arr);

P.S: Thanks to @mts-knn for mentioning the matter.

1 Comment

Note that splicing modifies the original array. If you add console.log(arr); to the end of your code snippet, it will log [], i.e. arr will be an empty array.
10

You can take this ES6 chunk function, which is easy to use:

const chunk = (array, size) =>
  Array.from({length: Math.ceil(array.length / size)}, (value, index) => array.slice(index * size, index * size + size));

const itemsPerChunk = 3;
const inputArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

const newArray = chunk(inputArray, itemsPerChunk);
console.log(newArray.length); // 3,

document.write(JSON.stringify(newArray)); //  [ [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ], [ 'g' ] ]

2 Comments

Love this one-liner mostly for it doesn't create any intermediate helper array but some rather small object.
Nice, I had similar, but with a default chunk size, and slightly more sugary slice params: const chunk = (array, n = 2) => Array.from({ length: Math.ceil(array.length / n) }, (_, i) => array.slice(i *= n, i + n))
10

js

function splitToBulks(arr, bulkSize = 20) {
    const bulks = [];
    for (let i = 0; i < Math.ceil(arr.length / bulkSize); i++) {
        bulks.push(arr.slice(i * bulkSize, (i + 1) * bulkSize));
    }
    return bulks;
}

console.log(splitToBulks([1, 2, 3, 4, 5, 6, 7], 3));

typescript

function splitToBulks<T>(arr: T[], bulkSize: number = 20): T[][] {
    const bulks: T[][] = [];
    for (let i = 0; i < Math.ceil(arr.length / bulkSize); i++) {
        bulks.push(arr.slice(i * bulkSize, (i + 1) * bulkSize));
    }
    return bulks;
}

Comments

9

If you use EcmaScript version >= 5.1, you can implement a functional version of chunk() using array.reduce() that has O(N) complexity:

function chunk(chunkSize, array) {
    return array.reduce(function(previous, current) {
        var chunk;
        if (previous.length === 0 || 
                previous[previous.length -1].length === chunkSize) {
            chunk = [];   // 1
            previous.push(chunk);   // 2
        }
        else {
            chunk = previous[previous.length -1];   // 3
        }
        chunk.push(current);   // 4
        return previous;   // 5
    }, []);   // 6
}

console.log(chunk(2, ['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b' ], [ 'c', 'd' ], [ 'e' ] ]

Explanation of each // nbr above:

  1. Create a new chunk if the previous value, i.e. the previously returned array of chunks, is empty or if the last previous chunk has chunkSize items
  2. Add the new chunk to the array of existing chunks
  3. Otherwise, the current chunk is the last chunk in the array of chunks
  4. Add the current value to the chunk
  5. Return the modified array of chunks
  6. Initialize the reduction by passing an empty array

Currying based on chunkSize:

var chunk3 = function(array) {
    return chunk(3, array);
};

console.log(chunk3(['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b', 'c' ], [ 'd', 'e' ] ]

You can add the chunk() function to the global Array object:

Object.defineProperty(Array.prototype, 'chunk', {
    value: function(chunkSize) {
        return this.reduce(function(previous, current) {
            var chunk;
            if (previous.length === 0 || 
                    previous[previous.length -1].length === chunkSize) {
                chunk = [];
                previous.push(chunk);
            }
            else {
                chunk = previous[previous.length -1];
            }
            chunk.push(current);
            return previous;
        }, []);
    }
});

console.log(['a', 'b', 'c', 'd', 'e'].chunk(4));
// prints [ [ 'a', 'b', 'c' 'd' ], [ 'e' ] ]

Comments

9

Use chunk from lodash

lodash.chunk(arr,<size>).forEach(chunk=>{
  console.log(chunk);
})

Comments

9

const array = ['a', 'b', 'c', 'd', 'e'];
const size = 2;
const chunks = [];
while (array.length) {
    chunks.push(array.splice(0, size));
}
console.log(chunks);

Comments

8
results = []
chunk_size = 10
while(array.length > 0){
   results.push(array.splice(0, chunk_size))
}

2 Comments

Not sure why this was down-voted, but the code could use some explanation.
Because splice is destructive to original array.
8

The one line in pure javascript:

function chunks(array, size) {
  return Array.apply(0,{length: Math.ceil(array.length / size)}).map((_, index) => array.slice(index*size, (index+1)*size))
}

// The following will group letters of the alphabet by 4
console.log(chunks([...Array(26)].map((x,i)=>String.fromCharCode(i + 97)), 4))

Comments

8

Here is an example where I split an array into chunks of 2 elements, simply by splicing chunks out of the array until the original array is empty.

    const array = [86,133,87,133,88,133,89,133,90,133];
    const new_array = [];

    const chunksize = 2;
    while (array.length) {
        const chunk = array.splice(0,chunksize);
        new_array.push(chunk);
    }

    console.log(new_array)

1 Comment

While this might answer the question, a bit of explanation would be extremely helpful, click edit and please type in some explanation.
8

You can use the Array.prototype.reduce function to do this in one line.

let arr = [1,2,3,4];
function chunk(arr, size)
{
    let result = arr.reduce((rows, key, index) => (index % size == 0 ? rows.push([key]) : rows[rows.length-1].push(key)) && rows, []);
    return result;
}
        
console.log(chunk(arr,2));

Comments

7
in coffeescript:

b = (a.splice(0, len) while a.length)

demo 
a = [1, 2, 3, 4, 5, 6, 7]

b = (a.splice(0, 2) while a.length)
[ [ 1, 2 ],
  [ 3, 4 ],
  [ 5, 6 ],
  [ 7 ] ]

2 Comments

a.splice(0, 2) removes the subarray of a[0..1] from a and returns the subarray a[0..1]. I am making an array of all those arrays
I recommend using the non-destructive slice() method instead of splice()

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.