Stellen Sie sich vor, ich habe ein JS-Array wie dieses:
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
Ich möchte dieses Array in N kleinere Arrays aufteilen. Zum Beispiel:
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]]
Für Python habe ich Folgendes:
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
Für JS ist die beste richtige Lösung, die ich finden könnte, eine rekursive Funktion, aber ich mag sie nicht, weil sie kompliziert und hässlich ist. Diese innere Funktion gibt ein Array wie dieses zurück [1, 2, 3, null, 4, 5, 6, null, 7, 8], und dann muss ich es erneut schleifen und manuell teilen. (Mein erster Versuch war, dies zurückzugeben: [1, 2, 3, [4, 5, 6, [7, 8, 9]]], und ich entschied mich, dies mit dem Nulltrennzeichen zu tun).
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));
}
Hier ist eine jsfiddle davon: http://jsfiddle.net/uduhH/
Wie würdest du das machen? Vielen Dank!
javascript
arrays
Tiago
quelle
quelle
split
Funktion ist nicht weit weg. Sie können dasnull
Unternehmen entfernen, indem Sie zwei Array-Wrapper hinzufügen:if (cols == 1) return [array]
undreturn [array.slice(0, size)].concat(split(array.slice(size), cols-1))
. Ich finde diese rekursive Version viel lesbarer als die meisten Antworten hier.Antworten:
Sie können die Slices "ausgeglichen" (die Längen der Subarrays unterscheiden sich so gering wie möglich) oder "gerade" (alle Subarrays außer den letzten haben die gleiche Länge) machen:
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>
quelle
var size = Math.ceil((len - i) / n--);
len - i
) durch die Anzahl der verbleibenden Blöcke (n--
)Ich denke, diese Art der Verwendung von Spleiß ist die sauberste:
splitToChunks(array, parts) { let result = []; for (let i = parts; i > 0; i--) { result.push(array.splice(0, Math.ceil(array.length / i))); } return result; }
Zum Beispiel
parts = 3
würden Sie 1/3, dann 1/2 des verbleibenden Teils und dann den Rest des Arrays nehmen.Math.ceil
stellt sicher, dass bei ungleichmäßiger Anzahl von Elementen die frühesten Blöcke erreicht werden.(Hinweis: Dadurch wird das ursprüngliche Array zerstört.)
quelle
function split(array, n) { let [...arr] = array; var res = []; while (arr.length) { res.push(arr.splice(0, n)); } return res; }
quelle
Ich habe gerade eine iterative Implementierung des Algorithmus vorgenommen: http://jsfiddle.net/ht22q/ . Es besteht Ihre Testfälle.
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; }
quelle
Sie können es in eine Matrix reduzieren. Im folgenden Beispiel wird das Array (
arr
) in eine Matrix aus Arrays mit zwei Positionen aufgeteilt. Wenn Sie andere Größen wünschen, ändern Sie einfach den Wert 2 in der zweiten Zeile:target.reduce((memo, value, index) => { if (index % 2 === 0 && index !== 0) memo.push([]) memo[memo.length - 1].push(value) return memo }, [[]])
Ich hoffe es hilft!
BEARBEITEN: Da einige Leute immer noch Kommentare abgeben, beantwortet dies die Frage nicht, da ich die Größe jedes Blocks anstelle der Anzahl der gewünschten Blöcke festgelegt habe. Hier kommt der Code, der erklärt, was ich im Kommentarbereich zu erklären versuche: Verwenden von
target.length
.// Chunk function const chunk = (target, size) => { return target.reduce((memo, value, index) => { // Here it comes the only difference if (index % (target.length / size) == 0 && index !== 0) memo.push([]) memo[memo.length - 1].push(value) return memo }, [[]]) } // Usage write(chunk([1, 2, 3, 4], 2)) write(chunk([1, 2, 3, 4], 4)) // For rendering pruposes. Ignore function write (content) { document.write(JSON.stringify(content), '</br>') }
quelle
function splitArr(arr, n) { return arr.reduce(function (a, i) { if (a[a.length - 1].length >= arr.length / n) { a.push([]) } a[a.length - 1].push(i) return a; }, [[]]) }
Update: 21.07.2020
Die Antwort, die ich vor einigen Jahren gegeben habe, funktioniert nur, wenn
originalArray.length
<=numCols
. Alternativ können Sie auch eine der folgenden Funktionen verwenden. Dadurch wird jedoch ein Layout erstellt, das nicht ganz der jeweiligen Frage entspricht (horizontale Sortierung statt vertikale Sortierung). AKA:[1,2,3,4]
->[[1,4],[2],[3]]
. Ich verstehe, dass dies immer noch einen Wert liefert, also lasse ich dies hier, aber ich empfehle Senthes Antwort .function splitArray(flatArray, numCols){ const newArray = [] for (let c = 0; c < numCols; c++) { newArray.push([]) } for (let i = 0; i < flatArray.length; i++) { const mod = i % numCols newArray[mod].push(flatArray[i]) } return newArray }
Ursprüngliche Antwort von 2017:
Alte Frage, aber da VanilleJS keine Voraussetzung ist und so viele versuchen, dies mit lodash / chunk zu lösen, und ohne zu verwechseln, was
_.chunk
tatsächlich geschieht, ist hier eine präzise und genaue Lösung mitlodash
:(Im Gegensatz zur akzeptierten Antwort garantiert dies auch n Spalten, selbst wenn
originalArray.length
<numCols
)import _chunk from 'lodash/chunk' /** * Split an array into n subarrays (or columns) * @param {Array} flatArray Doesn't necessarily have to be flat, but this func only works 1 level deep * @param {Number} numCols The desired number of columns * @return {Array} */ export function splitArray(flatArray, numCols){ const maxColLength = Math.ceil(flatArray.length/numCols) const nestedArray = _chunk(flatArray, maxColLength) let newArray = [] for (var i = 0; i < numCols; i++) { newArray[i] = nestedArray[i] || [] } return newArray }
Die
for
Schleife am Ende garantiert die gewünschte Anzahl von "Spalten".quelle
Rekursiver Ansatz, nicht getestet.
function splitArray(array, parts, out) { var len = array.length , partLen if (parts < len) { partLen = Math.ceil(len / parts); out.push(array.slice(0, partLen)); if (parts > 1) { splitArray(array.slice(partLen), parts - 1, out); } } else { out.push(array); } }
quelle
Ein anderes Rekursiv funktioniert ganz gut, es ist weniger hässlich
function nSmaller(num, arr, sliced) { var mySliced = sliced || []; if(num === 0) { return sliced; } var len = arr.length, point = Math.ceil(len/num), nextArr = arr.slice(point); mySliced.push(arr.slice(0, point)); nSmaller(num-1, nextArr, mySliced); return(mySliced); }
quelle
function parseToPages(elements, pageSize = 8) { var result = []; while (elements.length) { result.push(elements.splice(0, pageSize)); } return result; }
quelle
Wenn Sie die Größe der gewünschten Chunks im Voraus kennen, gibt es eine ziemlich elegante ES6-Methode:
const groupsOfFour = ([a,b,c,d, ...etc]) => etc.length? [[a,b,c,d], ...groupsOfFour(etc)] : [[a,b,c,d]]; console.log(groupsOfFour([1,2,3,4,1,2,3,4,1,2,3,4]));
Ich finde diese Notation ziemlich nützlich, um beispielsweise RGBA aus a zu analysieren
Uint8ClampedArray
.quelle
groupsOfFour( [ 1 ] )
gibt[ 1 , undefined, undefined, undefined ]
statt der erwarteten (und gewünschten) zurück[ [1] ]
.Wahrscheinlich wäre der sauberere Ansatz der folgende (ohne Verwendung einer anderen Bibliothek):
var myArray = []; for(var i=0; i<100; i++){ myArray.push(i+1); } console.log(myArray); function chunk(arr, size){ var chunkedArr = []; var noOfChunks = Math.ceil(arr.length/size); console.log(noOfChunks); for(var i=0; i<noOfChunks; i++){ chunkedArr.push(arr.slice(i*size, (i+1)*size)); } return chunkedArr; } var chunkedArr = chunk(myArray, 3); console.log(chunkedArr);
Ich habe mein eigenes Array erstellt, das aufgeteilt werden soll. Den Code finden Sie hier
Wir haben auch eine Methode "Chunk" in der Lodash-Bibliothek, die von großem Nutzen ist. hoffentlich hilft das
quelle
function splitArray(arr, numOfParts = 10){ const splitedArray = [] for (let i = 0; i < numOfParts;i++) { const numOfItemsToSplice = arr.length / 10; splitedArray.push(arr.splice(0, numOfItemsToSplice)) } return splitedArray; }
quelle
Mutation ist im Allgemeinen eine schlechte Sache.
Das ist schön, sauber und idempotent.
function partition(list = [], n = 1) { const isPositiveInteger = Number.isSafeInteger(n) && n > 0; if (!isPositiveInteger) { throw new RangeError('n must be a positive integer'); } const partitions = []; const partitionLength = Math.ceil(list.length / n); for (let i = 0; i < list.length; i += partitionLength) { const partition = list.slice(i, i+partitionLength); partitions.push( partition ); } return partitions; }
quelle
Ich habe es so gemacht, es funktioniert ...
function splitArray(array, parts) { if (parts< array.length && array.length > 1 && array != null) { var newArray = []; var counter1 = 0; var counter2 = 0; while (counter1 < parts) { newArray.push([]); counter1 += 1; } for (var i = 0; i < array.length; i++) { newArray[counter2++].push(array[i]); if (counter2 > parts - 1) counter2 = 0; } return newArray; } else return array; }
quelle
Überprüfen Sie meine Version dieses Array Split
// divide array Array.prototype.divideIt = function(d){ if(this.length <= d) return this; var arr = this, hold = [], ref = -1; for(var i = 0; i < arr.length; i++){ if(i % d === 0){ ref++; } if(typeof hold[ref] === 'undefined'){ hold[ref] = []; } hold[ref].push(arr[i]); } return hold; };
quelle
Wenn du weißt, dass du child_arrays.length setzen willst, dann denke ich, dass diese Lösung am besten ist:
function sp(size, arr){ //size - child_array.length var out = [],i = 0, n= Math.ceil((arr.length)/size); while(i < n) { out.push(arr.splice(0, (i==n-1) && size < arr.length ? arr.length: size)); i++;} return out; }
Rufen Sie fn: sp (2, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) // 2 - child_arrat.length auf
Antwort: [1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11]
quelle
Wenn Sie
lodash
einen funktionalen Programmieransatz verwenden können und möchten, habe ich Folgendes:const _ = require('lodash') function splitArray(array, numChunks) { return _.reduce(_.range(numChunks), ({array, result, numChunks}, chunkIndex) => { const numItems = Math.ceil(array.length / numChunks) const items = _.take(array, numItems) result.push(items) return { array: _.drop(array, numItems), result, numChunks: numChunks - 1 } }, { array, result: [], numChunks }).result }
quelle
Alles oben könnte gut funktionieren, aber was ist, wenn Sie ein
associative
Array mit Zeichenfolgen als Schlüssel haben?objectKeys = Object.keys; arraySplit(arr, n) { let counter = 0; for (const a of this.objectKeys(arr)) { this.arr[(counter%n)][a] = arr[a]; counter++; } }
quelle
Ich habe eine, die das ursprüngliche Array nicht verändert
function splitArray(array = [], nPieces = 1){ const splitArray = []; let atArrPos = 0; for(let i = 0; i < nPieces; i++){ const splitArrayLength = Math.ceil((array.length - atArrPos)/ (nPieces - i)); splitArray.push([]); splitArray[i] = array.slice(atArrPos, splitArrayLength + atArrPos); atArrPos += splitArrayLength; } return splitArray }
quelle
Sie können eine einfache rekursive Funktion verwenden
const chunkify = (limit, completeArray, finalArray = [])=>{ if(!completeArray.length) return finalArray const a = completeArray.splice(0,limit); return chunkify(limit, completeArray, [...finalArray,a]) }
quelle
splitToChunks(arrayvar, parts) { let result = []; for (let i = parts; i > 0; i--) { result.push(arrayvar.splice(0, Math.ceil(arrayvar.length / i))); } return result; }
quelle
Verwenden Sie einfach die Chunk-Funktion von lodash, um das Array in kleinere Arrays aufzuteilen. Https://lodash.com/docs#chunk Sie müssen nicht mehr mit den Schleifen herumspielen!
quelle
Wenn Sie lodash verwenden, können Sie es ziemlich einfach wie folgt erreichen:
import {chunk} from 'lodash'; // divides the array into 2 sections chunk([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 2); // => [[1,2,3,4,5,6], [7,8,9,10,11]]
quelle
_.chunk
Erstellt Arrays mit N Elementen, nicht mit N Arrays. Ihr Beispiel würde eine Ausgabe von 6 Arrays mit 2 Elementen in jedem haben, außer dem letzten[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11]]