Split array into chunks
JavascriptArraysSplitJavascript Problem Overview
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?
Javascript Solutions
Solution 1 - Javascript
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.
Solution 2 - Javascript
Here's a ES6 version using reduce
var perChunk = 2 // items per chunk
var inputArray = ['a','b','c','d','e']
var 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);
Solution 3 - Javascript
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));
}});
Solution 4 - Javascript
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;
Solution 5 - Javascript
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;
}
Solution 6 - Javascript
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]]
Solution 7 - Javascript
One-liner in ECMA 6
const [list,chunkSize] = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6]
[...Array(Math.ceil(list.length / chunkSize))].map(_ => list.splice(0,chunkSize))
Solution 8 - Javascript
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;
};
Solution 9 - Javascript
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!
Solution 10 - Javascript
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]]
Solution 11 - Javascript
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]]
Solution 12 - Javascript
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
}
Solution 13 - Javascript
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));
Solution 14 - Javascript
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);
Solution 15 - Javascript
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 part = <T>(a: T[], n: number): T[][] => {
const b = Math.ceil(a.length / n);
return [...Array(n)].map((_, i) => a.slice(i * b, (i + 1) * b));
};
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)));
Solution 16 - Javascript
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 :-)
Solution 17 - Javascript
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;
Solution 18 - Javascript
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.
Solution 19 - Javascript
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:
- 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 - Add the new chunk to the array of existing chunks
- Otherwise, the current chunk is the last chunk in the array of chunks
- Add the current value to the chunk
- Return the modified array of chunks
- 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' ] ]
Solution 20 - Javascript
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)
Solution 21 - Javascript
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;
}
Solution 22 - Javascript
results = []
chunk_size = 10
while(array.length > 0){
results.push(array.splice(0, chunk_size))
}
Solution 23 - Javascript
And this would be my contribution to this topic. I guess .reduce()
is the best way.
var segment = (arr, n) => arr.reduce((r,e,i) => i%n ? (r[r.length-1].push(e), r)
: (r.push([e]), r), []),
arr = Array.from({length: 31}).map((_,i) => i+1);
res = segment(arr,7);
console.log(JSON.stringify(res));
But the above implementation is not very efficient since .reduce()
runs through all arr
function. A more efficient approach (very close to the fastest imperative solution) would be, iterating over the reduced (to be chunked) array since we can calculate it's size in advance by Math.ceil(arr/n);
. Once we have the empty result array like Array(Math.ceil(arr.length/n)).fill();
the rest is to map slices of the arr
array into it.
function chunk(arr,n){
var r = Array(Math.ceil(arr.length/n)).fill();
return r.map((e,i) => arr.slice(i*n, i*n+n));
}
arr = Array.from({length: 31},(_,i) => i+1);
res = chunk(arr,7);
console.log(JSON.stringify(res));
So far so good but we can still simplify the above snipet further.
var chunk = (a,n) => Array.from({length: Math.ceil(a.length/n)}, (_,i) => a.slice(i*n, i*n+n)),
arr = Array.from({length: 31},(_,i) => i+1),
res = chunk(arr,7);
console.log(JSON.stringify(res));
Solution 24 - Javascript
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)
Solution 25 - Javascript
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))
Solution 26 - Javascript
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/
Solution 27 - Javascript
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));
Solution 28 - Javascript
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 ] ]
Solution 29 - Javascript
Use chunk from lodash
lodash.chunk(arr,<size>).forEach(chunk=>{
console.log(chunk);
})
Solution 30 - Javascript
const array = ['a', 'b', 'c', 'd', 'e'];
const size = 2;
const chunks = [];
while (array.length) {
chunks.push(array.splice(0, size));
}
console.log(chunks);
Solution 31 - Javascript
ES6 Generator version
function* chunkArray(array,size=1){
var clone = array.slice(0);
while (clone.length>0)
yield clone.splice(0,size);
};
var a = new Array(100).fill().map((x,index)=>index);
for(const c of chunkArray(a,10))
console.log(c);
Solution 32 - Javascript
ES6 spreads functional #ohmy #ftw
const chunk =
(size, xs) =>
xs.reduce(
(segments, _, index) =>
index % size === 0
? [...segments, xs.slice(index, index + size)]
: segments,
[]
);
console.log( chunk(3, [1, 2, 3, 4, 5, 6, 7, 8]) );
Solution 33 - Javascript
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' ] ]
Solution 34 - Javascript
For a functional solution, using Ramda:
Where popularProducts
is your input array, 5
is the chunk size
import splitEvery from 'ramda/src/splitEvery'
splitEvery(5, popularProducts).map((chunk, i) => {
// do something with chunk
})
Solution 35 - Javascript
Here's a recursive solution that is tail call optimize.
const splitEvery = (n, xs, y=[]) =>
xs.length===0 ? y : splitEvery(n, xs.slice(n), y.concat([xs.slice(0, n)]))
console.log(splitEvery(2, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
Solution 36 - Javascript
If you are using Underscore JS, just use :
var result = _.chunk(arr,elements_per_chunk)
Most projects already use underscore as a dependency, anyways.
Solution 37 - Javascript
ES6 one-line approach based on Array.prototype
reduce
and push
methods:
const doChunk = (list, size) => list.reduce((r, v) =>
(!r.length || r[r.length - 1].length === size ?
r.push([v]) : r[r.length - 1].push(v)) && r
, []);
console.log(doChunk([0,1,2,3,4,5,6,7,8,9,10,11,12], 5));
// [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12]]
Solution 38 - Javascript
This is the most efficient and straight-forward solution I could think of:
function chunk(array, chunkSize) {
let chunkCount = Math.ceil(array.length / chunkSize);
let chunks = new Array(chunkCount);
for(let i = 0, j = 0, k = chunkSize; i < chunkCount; ++i) {
chunks[i] = array.slice(j, k);
j = k;
k += chunkSize;
}
return chunks;
}
Solution 39 - Javascript
example with
unchanged source array
and not making all the chunks at once. (memory saver!)
const array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21];
const chunkSize = 4
for (var i = 0; i < array.length; i += chunkSize) {
const chunk = array.slice(i, i + chunkSize);
console.log('chunk=',chunk)
// do whatever
}
console.log('src array didnt changed. array=',array)
Solution 40 - Javascript
EDIT: @mblase75 added more concise code to the earlier answer while I was writing mine, so I recommend going with his solution.
You could use code like this:
var longArray = ["Element 1","Element 2","Element 3", /*...*/];
var smallerArrays = []; // will contain the sub-arrays of 10 elements each
var arraySize = 10;
for (var i=0;i<Math.ceil(longArray.length/arraySize);i++) {
smallerArrays.push(longArray.slice(i*arraySize,i*arraySize+arraySize));
}
Change the value of arraySize
to change the maximum length of the smaller arrays.
Solution 41 - Javascript
Here is a non-mutating solution using only recursion and slice().
const splitToChunks = (arr, chunkSize, acc = []) => (
arr.length > chunkSize ?
splitToChunks(
arr.slice(chunkSize),
chunkSize,
[...acc, arr.slice(0, chunkSize)]
) :
[...acc, arr]
);
Then simply use it like splitToChunks([1, 2, 3, 4, 5], 3)
to get [[1, 2, 3], [4, 5]]
.
Here is a fiddle for you to try out: https://jsfiddle.net/6wtrbx6k/2/
Solution 42 - Javascript
This is what i use, it might not be super fast, but it is compact and simple:
let chunksplit = (stream, size) => stream.reduce((chunks, item, idx, arr) => (idx % size == 0) ? [...chunks, arr.slice(idx, idx + size)] : chunks, []);
//if the index is a multiple of the chunksize, add new array
let testArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22];
document.write(JSON.stringify( chunksplit(testArray, 5) ));
//using JSON.stringify for the nested arrays to be shown
Solution 43 - Javascript
Here's my approach using Coffeescript list comprehension. A great article detailing comprehensions in Coffeescript can be found here.
chunk: (arr, size) ->
chunks = (arr.slice(index, index+size) for item, index in arr by size)
return chunks
Solution 44 - Javascript
Here is neat & optimised implemention of chunk()
function. Assuming default chunk size is 10
.
var chunk = function(list, chunkSize) {
if (!list.length) {
return [];
}
if (typeof chunkSize === undefined) {
chunkSize = 10;
}
var i, j, t, chunks = [];
for (i = 0, j = list.length; i < j; i += chunkSize) {
t = list.slice(i, i + chunkSize);
chunks.push(t);
}
return chunks;
};
//calling function
var list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var chunks = chunk(list);
Solution 45 - Javascript
This should be straightforward answer without many mathematical complications.
function chunkArray(array, sizeOfTheChunkedArray) {
const chunked = [];
for (let element of array) {
const last = chunked[chunked.length - 1];
if(!last || last.length === sizeOfTheChunkedArray) {
chunked.push([element])
} else {
last.push(element);
}
}
return chunked;
}
Solution 46 - Javascript
I created the following JSFiddle to demonstrate my approach to your question.
(function() {
// Sample arrays
var //elements = ["0", "1", "2", "3", "4", "5", "6", "7"],
elements = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43"];
var splitElements = [],
delimiter = 10; // Change this value as needed
// parameters: array, number of elements to split the array by
if(elements.length > delimiter){
splitElements = splitArray(elements, delimiter);
}
else {
// No need to do anything if the array's length is less than the delimiter
splitElements = elements;
}
//Displaying result in console
for(element in splitElements){
if(splitElements.hasOwnProperty(element)){
console.log(element + " | " + splitElements[element]);
}
}
})();
function splitArray(elements, delimiter) {
var elements_length = elements.length;
if (elements_length > delimiter) {
var myArrays = [], // parent array, used to store each sub array
first = 0, // used to capture the first element in each sub array
index = 0; // used to set the index of each sub array
for (var i = 0; i < elements_length; ++i) {
if (i % delimiter === 0) {
// Capture the first element of each sub array from the original array, when i is a modulus factor of the delimiter.
first = i;
} else if (delimiter - (i % delimiter) === 1) {
// Build each sub array, from the original array, sliced every time the i one minus the modulus factor of the delimiter.
index = (i + 1) / delimiter - 1;
myArrays[index] = elements.slice(first, i + 1);
}
else if(i + 1 === elements_length){
// Build the last sub array which contain delimiter number or less elements
myArrays[index + 1] = elements.slice(first, i + 1);
}
}
// Returned is an array of arrays
return myArrays;
}
}
First of all, I have two examples: an array with less than eight elements, another with an array with more than eight elements (comment whichever one you do not want to use).
I then check for the size of the array, simple but essential to avoid extra computation. From here if the array meets the criteria (array size > delimiter
) we move into the splitArray
function.
The splitArray
function takes in the delimiter (meaning 8, since that is what you want to split by), and the array itself. Since we are re-using the array length a lot, I am caching it in a variable, as well as the first
and last
.
first
represents the position of the first element in an array. This array is an array made of 8 elements. So in order to determine the first element we use the modulus operator.
myArrays
is the array of arrays. In it we will store at each index, any sub array of size 8 or below. This is the key strategy in the algorithm below.
index
represents the index for the myArrays
variable. Every time a sub array of 8 elements or less is to be stored, it needs to be stored in the corresponding index. So if we have 27 elements, that means 4 arrays. The first, second and third array will have 8 elements each. The last will have 3 elements only. So index
will be 0, 1, 2, and 3 respectively.
The tricky part is simply figuring out the math and optimizing it as best as possible. For example else if (delimiter - (i % delimiter) === 1)
this is to find the last element that should go in the array, when an array will be full (example: contain 10 elements).
This code works for every single scenario, you can even change the delimiter
to match any array size you'd like to get. Pretty sweet right :-)
Any questions? Feel free to ask in the comments below.
Solution 47 - Javascript
I just wrote this with the help of a groupBy function.
// utils
const group = (source) => ({
by: (grouping) => {
const groups = source.reduce((accumulator, item) => {
const name = JSON.stringify(grouping(item));
accumulator[name] = accumulator[name] || [];
accumulator[name].push(item);
return accumulator;
}, {});
return Object.keys(groups).map(key => groups[key]);
}
});
const chunk = (source, size) => group(source.map((item, index) => ({ item, index })))
.by(x => Math.floor(x.index / size))
.map(x => x.map(v => v.item));
// 103 items
const arr = [6,2,6,6,0,7,4,9,3,1,9,6,1,2,7,8,3,3,4,6,8,7,6,9,3,6,3,5,0,9,3,7,0,4,1,9,7,5,7,4,3,4,8,9,0,5,1,0,0,8,0,5,8,3,2,5,6,9,0,0,1,5,1,7,0,6,1,6,8,4,9,8,9,1,6,5,4,9,1,6,6,1,8,3,5,5,7,0,8,3,1,7,1,1,7,6,4,9,7,0,5,1,0];
const chunks = chunk(arr, 10);
console.log(JSON.stringify(chunks));
Solution 48 - Javascript
Hi try this -
function split(arr, howMany) {
var newArr = []; start = 0; end = howMany;
for(var i=1; i<= Math.ceil(arr.length / howMany); i++) {
newArr.push(arr.slice(start, end));
start = start + howMany;
end = end + howMany
}
console.log(newArr)
}
split([1,2,3,4,55,6,7,8,8,9],3)
Solution 49 - Javascript
Here's a version with tail recursion and array destructuring.
Far from the fastest performance, but I'm just amused that js can do this now. Even if it isn't optimized for it :(
const getChunks = (arr, chunk_size, acc = []) => {
if (arr.length === 0) { return acc }
const [hd, tl] = [ arr.slice(0, chunk_size), arr.slice(chunk_size) ]
return getChunks(tl, chunk_size, acc.concat([hd]))
}
// USAGE
const my_arr = [1,2,3,4,5,6,7,8,9]
const chunks = getChunks(my_arr, 2)
console.log(chunks) // [[1,2],[3,4], [5,6], [7,8], [9]]
Solution 50 - Javascript
There could be many solution to this problem.
one of my fav is:
function chunk(array, size) {
const chunked = [];
for (element of array){
let last = chunked[chunked.length - 1];
if(last && last.length != size){
last.push(element)
}else{
chunked.push([element])
}
}
return chunked;
}
function chunk1(array, size) {
const chunked = [];
let index = 0;
while(index < array.length){
chunked.push(array.slice(index,index+ size))
index += size;
}
return chunked;
}
console.log('chunk without slice:',chunk([1,2,3,4,5,5],2));
console.log('chunk with use of slice funtion',chunk1([1,2,3,4,5,6],2))
Solution 51 - Javascript
In case this is useful to anyone, this can be done very simply in RxJS 6:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
from(arr).pipe(bufferCount(3)).subscribe(chunk => console.log(chunk));
Outputs: [1, 2, 3] [4, 5, 6] [7, 8, 9] [10, 11, 12] [13, 14, 15] [16]
Solution 52 - Javascript
Late, here's my two cents. Like many said, I first would think of something like
chunker = (a,n) => [...Array(Math.ceil(a.length/n))].map((v,i) => a.slice(i*n, (i+1)*n))
But what I like better and haven't seen here is this:
chunker = (n) => (r,v,i) => (c = Math.floor(i/n), (r[c] = r[c] || []).push(v), r)
console.log(arr.reduce(chunker(3), []))
with longer variant
chunker = (a, n) => a.reduce((r,v,i) => {
c = Math.floor(i/n); // which chunk it belongs to
(r[c] = r[c] || []).push(v)
return r
}, [])
console.log(chunker(arr, 3))
Explanations
-
The common answer will first determine the number of chunks and then get slices of the original array based on what chunk is at and the size of each chunks
-
The chunker reducer function will go through each element and put it in the according evaluated chunk's array.
The performance is almost the same, the reduce method being 4% slower on average for what I could see.
PS: reduce(ing) has the advantage of easily change grouping criteria. In the question and examples the criteria is adjacent cells (and mapping uses slice for that). But you could want to do it in "cycles" for example, using mod (% operator), or any other math formulas
Re-reading it made me see that the formula could be a parameter too, leading to a more general solution and requiring 2 functions to achieve the answer:
splitter = (a, f) => a.reduce((r,v,i) => { // math formula and/or function
c = f(v, i) || 0; // custom formula, receiving each value and index
(r[c] = r[c] || []).push(v)
return r
}, [])
chunker = (a, n) => splitter(a, (v,i) => Math.floor(i/n))
console.log(chunker(arr, 3))
console.log(splitter(arr, (v,i) => v % 2)) // is it even or odd?
With little changes splitter
could also be used for making named-arrays aka objects, with function returning strings instead of numbers :)
Solution 53 - Javascript
I tried a recursive function…
const chunk = (arr, n) =>
arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : [];
…which is nice and short, but seems to take about 256× as long as @AymKdn’s answer for 1,000 elements, and 1,058× as long for 10,000 elements!
Solution 54 - Javascript
An efficient solution is to join solution with slice and push by indexChunk, the solution split into chunks:
function splitChunks(sourceArray, chunkSize) {
if(chunkSize <= 0)
throw "chunkSize must be greater than 0";
let result = [];
for (var i = 0; i < sourceArray.length; i += chunkSize) {
result[i / chunkSize] = sourceArray.slice(i, i + chunkSize);
}
return result;
}
let ar1 = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
];
console.log("Split in chunks with 4 size", splitChunks(ar1, 4));
console.log("Split in chunks with 7 size", splitChunks(ar1, 7));
Solution 55 - Javascript
# in coffeescript
# assume "ar" is the original array
# newAr is the new array of arrays
newAr = []
chunk = 10
for i in [0... ar.length] by chunk
newAr.push ar[i... i+chunk]
# or, print out the elements one line per chunk
for i in [0... ar.length] by chunk
console.log ar[i... i+chunk].join ' '
Solution 56 - Javascript
I changed BlazeMonger's slightly to use for a jQuery object..
var $list = $('li'),
$listRows = [];
for (var i = 0, len = $list.length, chunk = 4, n = 0; i < len; i += chunk, n++) {
$listRows[n] = $list.slice(i, i + chunk);
}
Solution 57 - Javascript
Here's a solution using ImmutableJS, where items
is an Immutable List and size
is the required grouping size.
const partition = ((items, size) => {
return items.groupBy((items, i) => Math.floor(i/size))
})
Solution 58 - Javascript
Her is a simple solution using @Blazemonger solution
function array_chunk(arr, size){
// initialize vars
var i,
j = arr.length,
tempArray = [];
// loop through and jump based on size
for (i=0; i<j; i+=size) {
// slice chunk of arr and push to tempArray
tempArray.push(arr.slice(i,i+size));
}
// return temp array (chunck)
return tempArray
}
This got the pipline flowing for me, hope this helps someone else out there. :)
Solution 59 - Javascript
Here's another solution with the reduce() method, though slightly different from other examples. Hopefully my explanation is a bit clearer as well.
var arr = [0, 1, 2, 3, 4, 5, 6, 7];
var chunkSize = 3;
arr = arr.reduce((acc, item, idx) => {
let group = acc.pop();
if (group.length == chunkSize) {
acc.push(group);
group = [];
}
group.push(item);
acc.push(group);
return acc;
}, [[]]);
console.log(arr); //Prints [[0, 1, 2], [3, 4, 5], [6, 7]]
Explanation
We call a reducer which, for each item in the array, gets the last item of the accumulator with pop()
. Remember that this item is an array which groups up to chunkSize
number of items (3 in this example).
If, and only if, this group has the array length equal to chunksize
we need to re-insert the group back into the accumulator and create a new group.
We then push the current item
into our group
array (which may already contain 0, 1 or 2 items from the previous steps). With the current item
inserted into the group
, we need to re-insert the group
back into the larger collection.
The process will repeat until we've iterated through all items in arr
.
Note that we have also provided the reducer with the starting value of an empty array inside an array with [[]]
.
Solution 60 - Javascript
Try this :
var oldArray = ["Banana", "Orange", "Lemon", "Apple", "Mango", "Banana", "Orange", "Lemon", "Apple", "Mango", "Banana", "Orange", "Lemon", "Apple", "Mango", "Banana", "Orange", "Lemon", "Apple", "Mango", "Banana", "Orange", "Lemon", "Apple", "Mango"];
var newArray = [];
while(oldArray.length){
let start = 0;
let end = 10;
newArray.push(oldArray.slice(start, end));
oldArray.splice(start, end);
}
console.log(newArray);
Solution 61 - Javascript
I prefer to use the splice method instead of slice. This solution uses the array length and chunk size to create a loop count and then loops over the array which gets smaller after every operation due to splicing in each step.
function chunk(array, size) {
let resultArray = [];
let chunkSize = array.length/size;
for(i=0; i<chunkSize; i++) {
resultArray.push(array.splice(0, size));
}
return console.log(resultArray);
}
chunk([1,2,3,4,5,6,7,8], 2);
If you dont want to mutate the original array, you can clone the original array using the spread operator and then use that array to solve the problem.
let clonedArray = [...OriginalArray]
Solution 62 - Javascript
my trick is to use parseInt(i/chunkSize)
and parseInt(i%chunkSize)
and then filling the array
// filling items
let array = [];
for(let i = 0; i< 543; i++)
array.push(i);
// printing the splitted array
console.log(getSplittedArray(array, 50));
// get the splitted array
function getSplittedArray(array, chunkSize){
let chunkedArray = [];
for(let i = 0; i<array.length; i++){
try{
chunkedArray[parseInt(i/chunkSize)][parseInt(i%chunkSize)] = array[i];
}catch(e){
chunkedArray[parseInt(i/chunkSize)] = [];
chunkedArray[parseInt(i/chunkSize)][parseInt(i%chunkSize)] = array[i];
}
}
return chunkedArray;
}
Solution 63 - Javascript
I solved it like this:
const chunks = [];
const chunkSize = 10;
for (let i = 0; i < arrayToSplit.length; i += chunkSize) {
const tempArray = arrayToSplit.slice(i, i + chunkSize);
chunks.push(tempArray);
}
Solution 64 - Javascript
Super late to the party but I solved a similar problem with the approach of using .join("")
to convert the array to one giant string, then using regex to .match(/.{1,7}/)
it into arrays of substrings of max length 7.
const arr = ['abc', 'def', 'gh', 'ijkl', 'm', 'nopq', 'rs', 'tuvwx', 'yz'];
const arrayOfSevens = arr.join("").match(/.{1,7}/g);
// ["abcdefg", "hijklmn", "opqrstu", "vwxyz"]
Would be interesting to see how this performs in a speed test against other methods
Solution 65 - Javascript
TypeScript version. Demonstrated is 101 random uid's split into groups of 10
const idArrayLengthLimit = 10;
const randomOneHundredOneIdArray = Array
.from(Array(101).keys())
.map(() => generateUid(5));
function generateUid(length: number) {
const uidString: string[] = [];
const uidChars = 'abcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
uidString
.push(uidChars.charAt(Math.floor(Math.random() * uidChars.length)));
}
return uidString.join('');
}
for (let i = 0; i < randomOneHundredOneIdArray.length; i++) {
if(i % idArrayLengthLimit === 0){
const result = randomOneHundredOneIdArray
.filter((_,id) => id >= i && id < i + idArrayLengthLimit);
// Observe result
console.log(result);
}
}
Solution 66 - Javascript
Here's a more specific case that someone might find valuable. I haven't seen it mentioned here yet.
What if you don't want constant/even chunk sizes, and instead want to specify the indices where the array is split. In that case, you can use this:
const splitArray = (array = [], splits = []) => {
array = [...array]; // make shallow copy to avoid mutating original
const chunks = []; // collect chunks
for (const split of splits.reverse()) chunks.push(array.splice(split)); // go backwards through split indices and lop off end of array
chunks.push(array); // add last remaining chunk (at beginning of array)
return chunks.reverse(); // restore chunk order
};
Then:
splitArray([1, 2, 3, 4, 5, 6, 7, 8, 9], [4, 6])
// [ [1, 2, 3, 4] , [5, 6] , [7, 8, 9] ]
Note that this will do funny things if you give it non-ascending/duplicate/negative/non-integer/etc split indices. You could add checks for these edge cases (e.g. Array.from(new Set(array))
to de-duplicate.
Solution 67 - Javascript
My favorite is the generator generateChunks
with the additional function getChunks
to execute the generator.
function* generateChunks(array, size) {
let start = 0;
while (start < array.length) {
yield array.slice(start, start + size);
start += size;
}
}
function getChunks(array, size) {
return [...generateChunks(array, size)];
}
console.log(getChunks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 3)) // [ [ 0, 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8 ], [ 9 ] ]
As an addition here the generator generatePartitions
with the further function getPartitions
to get n arrays of equal size.
function generatePartitions(array, count) {
return generateChunks(array, Math.ceil(array.length / count));
}
function getPartitions(array, count) {
return [...generatePartitions(array, count)];
}
console.log(getPartitions([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 3)) // [ [ 0, 1, 2, 3 ], [ 4, 5, 6, 7 ], [ 8, 9 ] ]
An advantage of the generator compared to many other solutions is that not multiple unnecessary arrays are created.
Solution 68 - Javascript
Well, a nice function for this would be:
function chunk(arr,times){
if(times===null){var times = 10} //Fallback for users wanting to use the default of ten
var tempArray = Array() //Array to be populated with chunks
for(i=0;i<arr.length/times;i++){
tempArray[i] = Array() //Sub-Arrays //Repeats for each chunk
for(j=0;j<times;j++){
if(!(arr[i*times+j]===undefined)){tempArray[i][j] = arr[i*times+j]//Populate Sub- Arrays with chunks
}
else{
j = times //Stop loop
i = arr.length/times //Stop loop
}
}
}
return tempArray //Return the populated and chunked array
}
Usage would be:
chunk(array,sizeOfChunks)
I commented it so you could understand what was going on.
(The formatting is a bit off, I programmed this on mobile)
Solution 69 - Javascript
Neat and clean easy to understand
let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let len = nums.length ;
const chunkArr = (arr, chunkNo) => {
let newArr = [];
for(let i = 0; i < len; i++){
if(nums[0] !== "" && nums[0] !== undefined ){
let a = nums.splice(0,chunkNo) ;
newArr.push(a);
}
}
return newArr ;
}
console.log(chunkArr(nums, 5));