ChatGPT解决这个技术问题 Extra ChatGPT

Split array into chunks

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?

Possible duplicate of Splitting a JS array into N arrays
For lodash users, your are looking for _.chunk.
if you need minimum size of the last chunk also, here are the options: stackoverflow.com/questions/57908133/…
I created a solution merged the best answers: stackoverflow.com/a/71483760/2290538

3
3limin4t0r

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.


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
R
Raphael Pinel

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); 

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!
a
adiga

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));
}});

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.
Pretty sure that should be array.map(function(i) not array.map(function(elem,i) though
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.
C
Community

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;

"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.
I
Ikechukwu Eze

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]]


I was surprised at all of the answers to this question that were almost using generators or using them in ways that were more complicated. Nice brevity and performance with this solution.
This is by far the best answer.
function* chunks<T>(arr: T[], n: number): Generator<T[], void> { and then use const foo = [ ...chunks( bar, 4 ) ]; - @RayFoss
A
AymKdn

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;
}

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.
C
Charlton Provatas

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))

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 splicing ahead, you may as well map the same array itself: var split=(fields,record=2)=>\n fields.map((field,index,fields)=>\n fields.splice(index,record,fields.slice(index,record)));
A
Arek Flinik

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;
};

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.
G
George Herolyants

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!


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.
r
rlemon

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]]

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) ) }
S
Steve Holgado

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]]

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
M
Matias Kinnunen

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
}

your reduce example is by far the cleanest way of doing it
G
Gergely Fehérvári

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));


u
user239558

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);

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()
n
nkitku

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))+'
'); document.write(JSON.stringify(part([1, 2, 3, 4, 5, 6, 7], 2)));


Thanks! The oneliner is the best answer!
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.
t
thoredge

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 :-)


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.
A
A1rPun

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;

@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/…
S
Sajeeb Ahamed

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.


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.
u
user1460043

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)

m
matsev

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' ] ]


B
Bar Nuri

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;
}

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

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

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))


K
Karol Be

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/


R
Rein F

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)


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

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));


R
Redu

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));


A
Arpit Jain
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 ] ]

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()
M
Milind Chaudhary

Use chunk from lodash

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

K
Khaled Ayed -ngCode-

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