I have an array of e-mails (it can be just 1 email, or 100 emails), and I need to send the array with an ajax request (that I know how to do), but I can only send an array that has 10 or less e-mails in it. So if there is an original array of 20 e-mails I will need to split them up into 2 arrays of 10 each. or if there are 15 e-mails in the original array, then 1 array of 10, and another array of 5. I'm using jQuery, what would be the best way to do this?
I have an array of e-mails (it can be just 1 email, or 100 emails), and I need to send the array with an ajax request (that I know how to do), but I can only send an array that has 10 or less e-mails in it. So if there is an original array of 20 e-mails I will need to split them up into 2 arrays of 10 each. or if there are 15 e-mails in the original array, then 1 array of 10, and another array of 5. I'm using jQuery, what would be the best way to do this?
Share Improve this question edited Oct 25, 2014 at 23:18 David Thomas 253k53 gold badges381 silver badges417 bronze badges asked Sep 1, 2011 at 16:52 BillBill 5,66817 gold badges66 silver badges97 bronze badges27 Answers
Reset to default 276Don't use jquery...use plain javascript
var a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var b = a.splice(0,10);
//a is now [11,12,13,14,15];
//b is now [1,2,3,4,5,6,7,8,9,10];
You could loop this to get the behavior you want.
var a = YOUR_ARRAY;
while(a.length) {
console.log(a.splice(0,10));
}
This would give you 10 elements at a time...if you have say 15 elements, you would get 1-10, the 11-15 as you wanted.
var size = 10; var arrayOfArrays = [];
for (var i=0; i<bigarray.length; i+=size) {
arrayOfArrays.push(bigarray.slice(i,i+size));
}
console.log(arrayOfArrays);
Unlike splice()
, slice()
is non-destructive to the original array.
You can use lodash: https://lodash.com/docs
_.chunk(['a', 'b', 'c', 'd'], 2);
// → [['a', 'b'], ['c', 'd']]
Just loop over the array, splicing it until it's all consumed.
var a = ['a','b','c','d','e','f','g']
, chunk
while (a.length > 0) {
chunk = a.splice(0,3)
console.log(chunk)
}
output
[ 'a', 'b', 'c' ]
[ 'd', 'e', 'f' ]
[ 'g' ]
Array.reduce could be inefficient for large arrays, especially with the mod operator. I think a cleaner (and possibly easier to read) functional solution would be this:
const chunkArray = (arr, size) =>
arr.length > size
? [arr.slice(0, size), ...chunkArray(arr.slice(size), size)]
: [arr];
Assuming you don't want to destroy the original array, you can use code like this to break up the long array into smaller arrays which you can then iterate over:
var longArray = []; // assume this has 100 or more email addresses in it
var shortArrays = [], i, len;
for (i = 0, len = longArray.length; i < len; i += 10) {
shortArrays.push(longArray.slice(i, i + 10));
}
// now you can iterate over shortArrays which is an
// array of arrays where each array has 10 or fewer
// of the original email addresses in it
for (i = 0, len = shortArrays.length; i < len; i++) {
// shortArrays[i] is an array of email addresss of 10 or less
}
Using ES6 Generators
Late to the party, but ES6 generators opened up another neat way to achieve what is asked for.
/**
* Returns chunks of size n.
* @param {Array<any>} array any array
* @param {number} n size of chunk
*/
function* chunks(array, n){
for(let i = 0; i < array.length; i += n) yield array.slice(i, i + n);
}
const result = [...chunks([1, 2, 3, 4, 5, 6, 7, 8 , 9, 10], 3)];
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Make it work for infinite Generators
Using the same idea you can create a generator which can also generate an infinite amount of n-sized
chunks from values retrieved from another (possibly infinite) generator function. This can be very handy to lazy-generate values once they are required which significantly reduces the required memory or it can even be used to generate a possibly infinite/ unknown number of chunks.
Here an example which uses two generators.
nextNaturalNumber()
is an infinite generator which always returns the next natural number. I am using the ES2020bigint
datatype here so there is no restriction (by JavaScript) for the size of the value.chunksFromIterable()
createsn-sized
chunks from an possibly infinite iterable.
/**
* Returns chunks of size n for a possibly infinite iterator.
* n must be >= 1
* @param {Iterable<any>} iterable any array
* @param {number} n size of chunk for n >= 1
*/
function* chunksFromIterable(iterable, n){
let arr = [];
let i = n;
for (const value of iterable) {
if(i <= 0) {
// another chunk of size n is filled => return chunk
yield arr;
arr = []; // create new empty array
i = n;
};
arr.push(value);
i--;
}
// in case the iterable is not infinite check if there are still values in the array and return them if necessary
if(arr.length > 0) yield arr;
}
/**
* Infinite iterator which always gets the next natural number.
*/
function* nextNaturalNumber(){
let i = 0n;
while(true) {
i += 1n;
yield i;
}
}
console.log("Finite iterable:");
// this version can now be used using the for ... of loop
for(const threeNaturalNumbers of chunksFromIterable([1, 2, 3, 4, 5, 6, 7, 8 , 9, 10], 3)){
console.log(threeNaturalNumbers);
}
console.log("Infinite iterable:");
// and it can also be used for this infinite generator
for(const threeNaturalNumbers of chunksFromIterable(nextNaturalNumber(), 3)){
printBigIntArray(threeNaturalNumbers);
if(threeNaturalNumbers[0] > 30) break; // end here to avoid an infinite loop
}
// helper function to print array of bigints as this does not seem to be working for snippets
function printBigIntArray(arr){
console.log(`[${arr.join(", ")}]`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another implementation:
const arr = ["H", "o", "w", " ", "t", "o", " ", "s", "p", "l", "i", "t", " ", "a", " ", "l", "o", "n", "g", " ", "a", "r", "r", "a", "y", " ", "i", "n", "t", "o", " ", "s", "m", "a", "l", "l", "e", "r", " ", "a", "r", "r", "a", "y", "s", ",", " ", "w", "i", "t", "h", " ", "J", "a", "v", "a", "S", "c", "r", "i", "p", "t"];
const size = 3;
const res = arr.reduce((acc, curr, i) => {
if ( !(i % size) ) { // if index is 0 or can be divided by the `size`...
acc.push(arr.slice(i, i + size)); // ..push a chunk of the original array to the accumulator
}
return acc;
}, []);
// => [["H", "o", "w"], [" ", "t", "o"], [" ", "s", "p"], ["l", "i", "t"], [" ", "a", " "], ["l", "o", "n"], ["g", " ", "a"], ["r", "r", "a"], ["y", " ", "i"], ["n", "t", "o"], [" ", "s", "m"], ["a", "l", "l"], ["e", "r", " "], ["a", "r", "r"], ["a", "y", "s"], [",", " ", "w"], ["i", "t", "h"], [" ", "J", "a"], ["v", "a", "S"], ["c", "r", "i"], ["p", "t"]]
NB - This does not modify the original array.
Or, if you prefer a functional, 100% immutable (although there's really nothing bad in mutating in place like done above) and self-contained method:
function splitBy(size, list) {
return list.reduce((acc, curr, i, self) => {
if ( !(i % size) ) {
return [
...acc,
self.slice(i, i + size),
];
}
return acc;
}, []);
}
As a supplement to @jyore's answer, and in case you still want to keep the original array:
var originalArray = [1,2,3,4,5,6,7,8];
var splitArray = function (arr, size) {
var arr2 = arr.slice(0),
arrays = [];
while (arr2.length > 0) {
arrays.push(arr2.splice(0, size));
}
return arrays;
}
splitArray(originalArray, 2);
// originalArray is still = [1,2,3,4,5,6,7,8];
I would like to share my solution as well. It's a little bit more verbose but works as well.
var data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var chunksize = 4;
var chunks = [];
data.forEach((item)=>{
if(!chunks.length || chunks[chunks.length-1].length == chunksize)
chunks.push([]);
chunks[chunks.length-1].push(item);
});
console.log(chunks);
Output (formatted):
[ [ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15 ] ]
You can start with an empty array and push inside it sections with your desired range from the original array at the same time you are subtracting from your original array until is empty.
const originalArr = [1,2,3,4,5,6,7,8,9,10,11];
const splittedArray = [];
while (originalArr.length > 0) {
splittedArray.push(originalArr.splice(0,range));
}
output for range 3
splittedArray === [[1,2,3][4,5,6][7,8,9][10,11]]
output for range 4
splittedArray === [[1,2,3,4][5,6,7,8][9,10,11]]
This is also good for a fronted pagination if want.
Another method:
var longArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var size = 2;
var newArray = new Array(Math.ceil(longArray.length / size)).fill("")
.map(function() { return this.splice(0, size) }, longArray.slice());
// newArray = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]];
This doesn't affect the original array as a copy, made using slice, is passed into the 'this' argument of map.
Another implementation, using Array.reduce (I think it’s the only one missing!):
const splitArray = (arr, size) =>
{
if (size === 0) {
return [];
}
return arr.reduce((split, element, index) => {
index % size === 0 ? split.push([element]) : split[Math.floor(index / size)].push(element);
return split;
}, []);
};
As many solutions above, this one’s non-destructive. Returning an empty array when the size is 0 is just a convention. If the if
block is omitted you get an error, which might be what you want.
More compact:
const chunk = (xs, size) =>
xs.map((_, i) =>
(i % size === 0 ? xs.slice(i, i + size) : null)).filter(Boolean);
// Usage:
const sampleArray = new Array(33).fill(undefined).map((_, i) => i);
console.log(chunk(sampleArray, 5));
function chunkArrayInGroups(arr, size) {
var newArr=[];
for (var i=0; i < arr.length; i+= size){
newArr.push(arr.slice(i,i+size));
}
return newArr;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3);
You can take a look at this code . Simple and Effective .
function chunkArrayInGroups(array, unit) {
var results = [],
length = Math.ceil(array.length / unit);
for (var i = 0; i < length; i++) {
results.push(array.slice(i * unit, (i + 1) * unit));
}
return results;
}
chunkArrayInGroups(["a", "b", "c", "d"], 2);
Here is a simple one liner
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);
console.log(segment(arr,7));
as a function
var arrayChunk = function (array, chunkSize) {
var arrayOfArrays = [];
if (array.length <= chunkSize) {
arrayOfArrays.push(array);
} else {
for (var i=0; i<array.length; i+=chunkSize) {
arrayOfArrays.push(array.slice(i,i+chunkSize));
}
}
return arrayOfArrays;
}
to use
arrayChunk(originalArray, 10) //10 being the chunk size.
using recursion
let myArr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
let size = 4; //Math.sqrt(myArr.length); --> For a n x n matrix
let tempArr = [];
function createMatrix(arr, i) {
if (arr.length !== 0) {
if(i % size == 0) {
tempArr.push(arr.splice(0,size))
}
createMatrix(arr, i - 1)
}
}
createMatrix(myArr, myArr.length);
console.log(tempArr);
Note: The existing array i.e. myArr will be modified.
using prototype we can set directly to array class
Array.prototype.chunk = function(n) {
if (!this.length) {
return [];
}
return [this.slice(0, n)].concat(this.slice(n).chunk(n));
};
console.log([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].chunk(5));
let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
let size = 5;
let fragments = Array.from(Array(Math.ceil(a.length / size))).map((_,index) => a.slice(index * size,(index + 1) * size))
You can use the below function if you know the number array (numGroups) to be split.
function createGroups(arr, numGroups) {
const perGroup = Math.ceil(arr.length / numGroups);
return new Array(numGroups)
.fill('')
.map((_, i) => arr.slice(i * perGroup, (i + 1) * perGroup));
}
Sample Use:
createGroups([0, 1, 2, 3, 4, 5, 6], 3); //arr = [0, 1, 2, 3, 4, 5, 6] and numGroups = 3
If you want a method that doesn't modify the existing array, try this:
let oldArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
let newArray = [];
let size = 3; // Size of chunks you are after
let j = 0; // This helps us keep track of the child arrays
for (var i = 0; i < oldArray.length; i++) {
if (i % size === 0) {
j++
}
if(!newArray[j]) newArray[j] = [];
newArray[j].push(oldArray[i])
}
function chunkArrayInGroups(arr, size) {
var newArr=[];
for (var i=0; arr.length>size; i++){
newArr.push(arr.splice(0,size));
}
newArr.push(arr.slice(0));
return newArr;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3);
You can use the following code to achieve the required functionality
const splitter = (arr, splitBy, cache = []) => {
const tmp = [...arr]
while (tmp.length) cache.push(tmp.splice(0, splitBy))
return cache
}
const split = splitter([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21], 10)
console.log(split);
Notice, it was an array of length 22 then the splitter function splits it into 2 smaller arrays of 10 items and 1 array of 2 items.
let a = [1, 2, 3, 4, 6, 7, 8, 9, 10, 11];
let _splitCount = 3;
let b = a.reduce((acc, curr, index) => {
if (index % _splitCount === 0) {
acc.push([curr]);
} else {
acc[acc.length - 1].push(curr);
}
return acc;
}, []);
this is the easy solution i think❤️
You could use map+filter as an alternative to reduce:
a.map((x,i,a,chunk=3)=>i%chunk ? null: a.slice(i,i+chunk)).filter(x=>x)