Angenommen, ich habe ein Javascript-Array, das wie folgt aussieht:
["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
Welcher Ansatz wäre geeignet, um das Array in viele kleinere Arrays mit beispielsweise höchstens 10 Elementen aufzuteilen (aufzuteilen)?
javascript
arrays
split
Industriell
quelle
quelle
const chunk = (arr, n) => arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []
was nett und kurz ist, aber ungefähr 256 × so lange zu dauern scheint wie @ AymKdns Antwort für 1.000 Elemente und 1.058 × so lange für 10.000 Elemente!Antworten:
Die array.slice- Methode kann ein Slice vom Anfang, der Mitte oder dem Ende eines Arrays für beliebige Zwecke extrahieren, ohne das ursprüngliche Array zu ändern.
quelle
chunk
Sein zu behaupten0
. (Endlosschleife)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));
.Geändert von einer Antwort von dbaseman: https://stackoverflow.com/a/10456344/711085
kleiner Nachtrag :
Ich sollte darauf hinweisen, dass das oben Genannte eine meiner Meinung nach nicht so elegante Problemumgehung ist
Array.map
. Grundsätzlich wird Folgendes ausgeführt, wobei ~ Verkettung ist:Es hat die gleiche asymptotische Laufzeit wie die folgende Methode, aber möglicherweise einen schlechteren konstanten Faktor, da leere Listen erstellt werden. Man könnte dies wie folgt umschreiben (meistens das gleiche wie Blazemongers Methode, weshalb ich diese Antwort ursprünglich nicht eingereicht habe):
Effizientere Methode:
Mein bevorzugter Weg ist heutzutage der oben genannte oder einer der folgenden:
Demo:
Oder wenn Sie keine Array.range-Funktion möchten, handelt es sich tatsächlich nur um einen Einzeiler (ohne Flusen):
oder
quelle
chunk
Funktion auf dem Array erhalten, die zusätzliche Komplexität, die Sie hinzufügen, und die subtilen Fehler, die das Durcheinander mit integrierten Prototypen verursachen kann, nicht wirklich überwiegt.array.map(function(i)
nichtarray.map(function(elem,i)
obwohlHier ist eine ES6-Version mit Reduce
Und Sie sind bereit, weitere Karten- / Reduktions-Transformationen zu verketten. Ihr Eingabearray bleibt erhalten
Wenn Sie eine kürzere, aber weniger lesbare Version bevorzugen, können Sie einige davon
concat
in die Mischung streuen, um das gleiche Endergebnis zu erzielen:quelle
5/2 = 2.5
undMath.floor(2.5) = 2
so wird Gegenstand mit Index 5 in Eimer 2 gelegtVermeiden Sie es, mit nativen Prototypen, einschließlich Array.prototype, herumzuspielen, wenn Sie nicht wissen, wer Ihren Code verbraucht (Dritte, Mitarbeiter, Sie selbst zu einem späteren Zeitpunkt usw.).
Es gibt Möglichkeiten, Prototypen sicher zu erweitern (jedoch nicht in allen Browsern), und es gibt Möglichkeiten, Objekte, die aus erweiterten Prototypen erstellt wurden, sicher zu konsumieren. Eine bessere Faustregel besteht jedoch darin, dem Prinzip der geringsten Überraschung zu folgen und diese Praktiken insgesamt zu vermeiden.
Wenn Sie etwas Zeit haben, lesen Sie Andrew Duponts JSConf 2011-Vortrag "Alles ist erlaubt: Erweitern von integrierten Funktionen" , um eine gute Diskussion zu diesem Thema zu erhalten.
Zurück zur Frage: Die oben genannten Lösungen funktionieren zwar, sind jedoch zu komplex und erfordern unnötigen Rechenaufwand. Hier ist meine Lösung:
quelle
Ich habe die verschiedenen Antworten auf jsperf.com getestet. Das Ergebnis ist dort verfügbar: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds
Und die schnellste Funktion (und das funktioniert ab IE8) ist diese:
quelle
Ich würde lieber die Spleißmethode verwenden:
quelle
var clone = [...array]
Führen Sie dann die Längenprüfung durch und spleißen Sie über das geklonte Array.array = array.slice()
eine flache Kopie erstellen.Einzeiler in ECMA 6
quelle
list
Array.map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
Alte Frage: Neue Antwort! Ich habe tatsächlich mit einer Antwort auf diese Frage gearbeitet und einen Freund dazu gebracht, sie zu verbessern! Hier ist es also:
quelle
.length
viel größer als die Blockgröße istn
). Wenn dies eine faule Sprache wäre (im Gegensatz zu Javascript), würde dieser Algorithmus nicht unter O (N ^ 2) -Zeit leiden. Die rekursive Implementierung ist jedoch elegant. Sie können es wahrscheinlich ändern, um die Leistung zu verbessern, indem Sie zuerst eine wiederkehrende Hilfsfunktion definierenarray,position
und dann Folgendes auslösen : GibtArray.prototype.chunk
[Ihrevar chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
Heutzutage können Sie die Chunk-Funktion von lodash verwenden, um das Array in kleinere Arrays aufzuteilen. Https://lodash.com/docs#chunk Sie müssen nicht mehr mit den Schleifen herumspielen!
quelle
Es gab viele Antworten, aber das ist, was ich benutze:
Suchen Sie zunächst nach einem Rest, wenn Sie den Index durch die Blockgröße dividieren.
Wenn es einen Rest gibt, geben Sie einfach das Akkumulator-Array zurück.
Wenn es keinen Rest gibt, ist der Index durch die Blockgröße teilbar. Nehmen Sie also einen Slice aus dem ursprünglichen Array (beginnend mit dem aktuellen Index) und fügen Sie ihn dem Akkumulator-Array hinzu.
Das zurückgegebene Akkumulator-Array für jede Iteration von Reduce sieht also ungefähr so aus:
quelle
Generatoren verwenden
quelle
Ok, fangen wir mit einem ziemlich engen an:
Welches wird so verwendet:
Dann haben wir diese enge Reduzierfunktion:
Welches wird so verwendet:
Da ein Kätzchen stirbt, wenn wir uns
this
an eine Zahl binden , können wir stattdessen wie folgt manuell curryen:Welches wird so verwendet:
Dann die immer noch ziemlich enge Funktion, die alles auf einmal erledigt:
quelle
(p[i/n|0] || (p[i/n|0] = []))
, damit Sie keinen Wert zuweisen, wenn nicht notwendig ...Ich wollte eine einfache, nicht mutierende Lösung in reinem ES6 erstellen. Besonderheiten in Javascript machen es erforderlich, das leere Array vor dem Mapping zu füllen :-(
Diese Version mit Rekursion scheint einfacher und überzeugender zu sein:
Die lächerlich schwachen Array-Funktionen von ES6 sorgen für gute Rätsel :-)
quelle
0
aus dem entfernenfill
, was dasfill
Aussehen ein wenig vernünftiger macht, imho.Ich denke, dies ist eine schöne rekursive Lösung mit ES6-Syntax:
quelle
Erstellt ein npm-Paket für dieses https://www.npmjs.com/package/array.chunk
Bei Verwendung eines TypedArray
quelle
slice
Methode fürTypedArray
, wir könnensubarray
stattdessen developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Wenn Sie die EcmaScript-Version> = 5.1 verwenden, können Sie eine funktionale Version der
chunk()
Verwendung von array.reduce () mit O (N) -Komplexität implementieren :Erklärung von jedem
// nbr
oben:chunkSize
Elemente enthältCurrying basierend auf
chunkSize
:Sie können die
chunk()
Funktion zum globalenArray
Objekt hinzufügen :quelle
quelle
quelle
Der folgende ES2015-Ansatz funktioniert ohne Definition einer Funktion und direkt auf anonymen Arrays (Beispiel mit Blockgröße 2):
Wenn Sie eine Funktion dafür definieren möchten, können Sie dies wie folgt tun (Verbesserung des Kommentars von K ._ zu Blazemongers Antwort ):
quelle
Und das wäre mein Beitrag zu diesem Thema. Ich denke, das
.reduce()
ist der beste Weg.Die obige Implementierung ist jedoch nicht sehr effizient, da
.reduce()
sie allearr
Funktionen durchläuft . Ein effizienterer Ansatz (der der schnellsten imperativen Lösung sehr nahe kommt) wäre, über das reduzierte (zu zerteilende) Array zu iterieren, da wir seine Größe im Voraus durch berechnen könnenMath.ceil(arr/n);
. Sobald wir das leere Ergebnisarray haben, müssen wir wieArray(Math.ceil(arr.length/n)).fill();
der Rest Slices desarr
Arrays darauf abbilden .quelle
Verwenden Sie ein Stück von lodash
quelle
Eine weitere Lösung mit
arr.reduce()
:Diese Lösung ist der Lösung von Steve Holgado sehr ähnlich . Da diese Lösung jedoch keine Array-Streuung verwendet und keine neuen Arrays in der Reduzierungsfunktion erstellt, ist sie schneller (siehe jsPerf-Test ) und subjektiv besser lesbar (einfachere Syntax) als die andere Lösung.
Bei jeder n-ten Iteration (wobei n =
size
; beginnend mit der ersten Iteration) wird dem Akkumulatorarray (acc
) ein Teil des Arrays angehängt (arr.slice(i, i + size)
) und dann zurückgegeben. Bei anderen Iterationen wird das Akkumulatorarray unverändert zurückgegeben.Wenn
size
Null ist, gibt die Methode ein leeres Array zurück. Wenn diessize
negativ ist, gibt die Methode fehlerhafte Ergebnisse zurück. Wenn dies in Ihrem Fall erforderlich ist, möchten Sie möglicherweise etwas gegen negative oder nicht positivesize
Werte unternehmen .Wenn in Ihrem Fall die Geschwindigkeit wichtig ist, ist eine einfache
for
Schleife schneller als die Verwendungarr.reduce()
(siehe jsPerf-Test ), und einige finden diesen Stil möglicherweise auch besser lesbar:quelle
Für eine funktionale Lösung mit Ramda :
Wo
popularProducts
ist Ihr Eingabearray,5
ist die Blockgrößequelle
Einzeiliger ES6-Ansatz basierend auf
Array.prototype
reduce
undpush
Methoden:quelle
ES6 Generator Version
quelle
const
stattdessen.Dies ist die effizienteste und einfachste Lösung, die ich mir vorstellen kann:
quelle
ES6 verbreitet funktionale #ohmy #ftw
quelle
Hier ist eine rekursive Lösung, die Tail Call Optimize ist.
quelle
BEARBEITEN: @ mblase75 hat der früheren Antwort während des Schreibens meiner Antwort einen präziseren Code hinzugefügt, daher empfehle ich, mit seiner Lösung fortzufahren.
Sie könnten folgenden Code verwenden:
Ändern Sie den Wert von
arraySize
, um die maximale Länge der kleineren Arrays zu ändern.quelle
Hier ist eine nicht mutierende Lösung, die nur Rekursion und Slice () verwendet.
Dann benutze es einfach gerne um
splitToChunks([1, 2, 3, 4, 5], 3)
zu bekommen[[1, 2, 3], [4, 5]]
.Hier ist eine Geige, die Sie ausprobieren können: https://jsfiddle.net/6wtrbx6k/2/
quelle