I need to split a javascript array into n sized chunks.

E.g.: Given this array

["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"]

and a n equals to 4, the output should be this:

[ ["a1", "a2", "a3", "a4"],
  ["a5", "a6", "a7", "a8"],
  ["a9", "a10", "a11", "a12"],
  ["a13"]
]

I aware of pure javascript solutions for this problem, but since I am already using underscore.js I am wondering if underscore provides a better solution for this.

Edit:

I created a jsPerf test to check how much slower the underscore solution is.

share|improve this question
up vote 68 down vote accepted

Take a look at lodash' chunk: https://lodash.com/docs#chunk

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
_.chunk(data, 3); 
// [
//  ["a1", "a2", "a3"],
//  ["a4", "a5", "a6"],
//  ["a7", "a8", "a9"],
//  ["a10", "a11", "a12"],
//  ["a13"]
// ]
share|improve this answer
7  
This should be the accepted answer – Jonah Aug 22 '16 at 5:10
    
It would be helpful if lodash and underscore both backwards compatible APIs – Jonno_FTW Nov 2 '16 at 5:26
    
@Jonah That's true. The previous answer is not longer the best one, therefore I updated the accepted answer for the sake of the readers :) – Cesar Canassa Mar 21 at 21:16

For Underscore based solution try this:

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
var n = 3;
var lists = _.groupBy(data, function(element, index){
  return Math.floor(index/n);
});
lists = _.toArray(lists); //Added this to convert the returned object to an array.
console.log(lists);

Using the chain wrapper method you can combine the two statements as below:

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
var n = 3;
var lists = _.chain(data).groupBy(function(element, index){
  return Math.floor(index/n);
}).toArray()
.value();
share|improve this answer
1  
Thanks! works like a charm. – Cesar Canassa Dec 19 '11 at 20:07
1  
Weirdly, Underscore's groupBy returns an object, not an array. Not a dealbreaker--you get basically the same functionality--but an odd bit of semantics. Edit: Oh, it does that to maintain chainability. Still interesting. – Jordan Running Dec 19 '11 at 20:09
    
@Cesar Canassa: For the sake of future developers who read that code, please consider putting that as a function in a custom library if you will use it a lot, or commenting it well if you won't :) – Briguy37 Dec 19 '11 at 20:12
    
@Jordan: Didn't realize that. Edited the answer to conver the object to array. – Chandu Dec 19 '11 at 20:14
1  
This is no longer the best solution. Please use chunk() instead – Jonah Aug 22 '16 at 5:11

A possibly simpler expression:

    _.range(coll.length / n).map(i => coll.slice(i * n, (i + 1) * n))
share|improve this answer
    
Simpler than what? Answers should stand alone. – Nathan Tuggy Oct 27 '15 at 1:10

try this one it is much more practical (for example, if you would want to split the array based on amount of items to be container in each sub array):

function chunk(arr, start, amount){
    var result = [], 
        i, 
        start = start || 0, 
        amount = amount || 500, 
        len = arr.length;

    do {
        //console.log('appending ', start, '-', start + amount, 'of ', len, '.');
        result.push(arr.slice(start, start+amount));
        start += amount;

    } while (start< len);

    return result;
};

and the use in your case:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
    chunked = chunk(arr, 0, Math.floor(arr.length/3)); //to get 4 nested arrays

console.log(chunked);

and another case:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
    chunked = chunk(arr, 0, 3); // to get 6 nested arrays each containing maximum of 3 items

console.log(chunked);
share|improve this answer
    
That start parameter is not really practical imho. You usually would not want to pass it; but you always need to specify the chunk size. Better swap those two parameters. – Bergi Feb 7 '15 at 11:14
    
Why is this a do while loop? No one wants to get empty chunks. – Bergi Feb 7 '15 at 11:14

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.