Imagine I have an JS array like this:
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
What I want is to split that array into N smaller arrays. For instance:
split_list_in_n(a, 2) [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11]] For N = 3: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11]] For N = 4: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11]] For N = 5: [[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]
For Python, I have this:
def split_list_in_n(l, cols): """ Split up a list in n lists evenly size chuncks """ start = 0 for i in xrange(cols): stop = start + len(l[i::cols]) yield l[start:stop] start = stop
For JS, the best right solution that I could come up with is a recursive function, but I don't like it because it's complicated and ugly. This inner function returns an array like this [1, 2, 3, null, 4, 5, 6, null, 7, 8], and then I have to loop it again and split it manually. (My first attempt was returning this: [1, 2, 3, [4, 5, 6, [7, 8, 9]]], and I decided to do it with the null separator).
function split(array, cols) { if (cols==1) return array; var size = Math.ceil(array.length / cols); return array.slice(0, size).concat([null]).concat(split(array.slice(size), cols-1)); }
Here's a jsfiddle of that: http://jsfiddle.net/uduhH/
How would you do that? Thanks!
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With