Splitting a JS array into N arrays
You can make the slices "balanced" (subarrays' lengths differ as less as possible) or "even" (all subarrays but the last have the same length):
function chunkify(a, n, balanced) {
if (n < 2)
return [a];
var len = a.length,
out = [],
i = 0,
size;
if (len % n === 0) {
size = Math.floor(len / n);
while (i < len) {
out.push(a.slice(i, i += size));
}
}
else if (balanced) {
while (i < len) {
size = Math.ceil((len - i) / n--);
out.push(a.slice(i, i += size));
}
}
else {
n--;
size = Math.floor(len / n);
if (len % size === 0)
size--;
while (i < size * n) {
out.push(a.slice(i, i += size));
}
out.push(a.slice(size * n));
}
return out;
}
///////////////////////
onload = function () {
function $(x) {
return document.getElementById(x);
}
function calc() {
var s = +$('s').value, a = [];
while (s--)
a.unshift(s);
var n = +$('n').value;
$('b').textContent = JSON.stringify(chunkify(a, n, true))
$('e').textContent = JSON.stringify(chunkify(a, n, false))
}
$('s').addEventListener('input', calc);
$('n').addEventListener('input', calc);
calc();
}
<p>slice <input type="number" value="20" id="s"> items into
<input type="number" value="6" id="n"> chunks:</p>
<pre id="b"></pre>
<pre id="e"></pre>
I think this way using splice is the cleanest:
splitToChunks(array, parts) {
let result = [];
for (let i = parts; i > 0; i--) {
result.push(array.splice(0, Math.ceil(array.length / i)));
}
return result;
}
For example, for parts = 3
, you would take 1/3, then 1/2 of the remaining part, then the rest of the array. Math.ceil
ensures that in case of uneven number of elements they will go to the earliest chunks.
(Note: this destroys the initial array.)
function split(array, n) {
let [...arr] = array;
var res = [];
while (arr.length) {
res.push(arr.splice(0, n));
}
return res;
}
I just made an iterative implementation of the algorithm: http://jsfiddle.net/ht22q/. It passes your test cases.
function splitUp(arr, n) {
var rest = arr.length % n, // how much to divide
restUsed = rest, // to keep track of the division over the elements
partLength = Math.floor(arr.length / n),
result = [];
for(var i = 0; i < arr.length; i += partLength) {
var end = partLength + i,
add = false;
if(rest !== 0 && restUsed) { // should add one element for the division
end++;
restUsed--; // we've used one division element now
add = true;
}
result.push(arr.slice(i, end)); // part of the array
if(add) {
i++; // also increment i in the case we added an extra element for division
}
}
return result;
}