Ich habe ein JavaScript-Array wie:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
Wie würde ich vorgehen, um die einzelnen inneren Arrays zu einem zusammenzuführen:
["$6", "$12", "$25", ...]
javascript
arrays
flatten
Andy
quelle
quelle
reduce
+ verwenden,concat
sind O ((N ^ 2) / 2), wobei als akzeptierte Antwort (nur ein Aufruf anconcat
) höchstens O (N * 2) in einem schlechten Browser und O (N) in a gut. Auch Denys Lösung ist für die eigentliche Frage optimiert und bis zu 2x schneller als die einzelneconcat
. Für diereduce
Leute macht es Spaß, sich beim Schreiben von winzigem Code cool zu fühlen, aber wenn das Array beispielsweise 1000 Subarrays mit einem Element hätte, würden alle Reduce + Concat-Lösungen 500500 Operationen ausführen, während die einzelne Concat- oder einfache Schleife 1000 Operationen ausführen würde.[].concat(...array)
array.flat(Infinity)
WoInfinity
ist die maximale Tiefe zum Abflachen?Antworten:
Sie können
concat
Arrays zusammenführen:Bei Verwendung der
apply
Methode vonconcat
wird nur der zweite Parameter als Array verwendet, sodass die letzte Zeile mit dieser identisch ist:Es gibt auch die
Array.prototype.flat()
in ES2019 eingeführte Methode, mit der Sie die Arrays reduzieren können, obwohl sie nur in Node.js ab Version 11 und überhaupt nicht in Internet Explorer verfügbar ist .quelle
concat
Quellarray nicht geändert wird, sodass dasmerged
Array nach dem Aufruf von leer bleibtconcat
. Besser etwas zu sagen wie:merged = merged.concat.apply(merged, arrays);
var merged = [].concat.apply([], arrays);
scheint gut zu funktionieren, um es in eine Zeile zu bekommen. edit: wie Nikitas Antwort schon zeigt.Array.prototype.concat.apply([], arrays)
.var merged = [].concat(...arrays)
Hier ist eine kurze Funktion, die einige der neueren JavaScript-Array-Methoden verwendet, um ein n-dimensionales Array zu reduzieren.
Verwendungszweck:
quelle
flat
beim ersten Aufruf der an übergebenen anonymen Funktionreduce
. Wenn es nicht angegeben wird,reduce
bindet der erste Aufruf zum Binden den ersten Wert aus dem Array anflat
, was schließlich dazu führen würde,1
dass erflat
in beiden Beispielen gebunden wird .1.concat
ist keine Funktion.const flatten = (arr) => arr.reduce((flat, next) => flat.concat(next), []);
const flatten = (arr) => arr.reduce((flat, next) => flat.concat(Array.isArray(next) ? flatten(next) : next), []);
Es gibt eine verwirrend versteckte Methode, die ein neues Array erstellt, ohne das ursprüngliche zu mutieren:
quelle
[].concat([[1],[2,3],[4]]...)
[[1],[2,3],[4]]
als Ergebnis. Die von @Nikita angebotene Lösung ist sowohl für CoffeeScript als auch für JS korrekt.[].concat([1],[2,3],[4],...)
....
ist tatsächlicher Code, nicht einig Auslassungspunkte.Dies kann am besten mit der Javascript-Reduktionsfunktion erfolgen.
Oder mit ES2015:
js-Geige
Mozilla-Dokumente
quelle
[]
und es sind keine weiteren Validierungen erforderlich.arrays.reduce((flatten, arr) => [...flatten, ...arr])
Es gibt eine neue native Methode namens flat , um dies genau zu tun.
(Ab Ende 2019
flat
ist es jetzt im ECMA 2019-Standard veröffentlicht undcore-js@3
(Babels Bibliothek) enthält es in ihrer Polyfill- Bibliothek. )quelle
Die meisten Antworten hier funktionieren nicht auf großen Arrays (z. B. 200 000 Elemente), und selbst wenn dies der Fall ist, sind sie langsam. Die Antwort von polkovnikov.ph hat die beste Leistung, funktioniert jedoch nicht bei tiefer Abflachung.
Hier ist die schnellste Lösung, die auch auf Arrays mit mehreren Verschachtelungsebenen funktioniert :
Beispiele
Riesige Arrays
Es handhabt große Arrays ganz gut. Auf meinem Computer dauert die Ausführung dieses Codes ca. 14 ms.
Verschachtelte Arrays
Es funktioniert mit verschachtelten Arrays. Dieser Code erzeugt
[1, 1, 1, 1, 1, 1, 1, 1]
.Arrays mit unterschiedlichen Verschachtelungsebenen
Es gibt keine Probleme mit dem Reduzieren von Arrays wie diesem.
quelle
RangeError: Maximum call stack size exceeded
). Für ein Array mit 20 000 Elementen dauert es 2-5 Millisekunden.Update: Es stellte sich heraus, dass diese Lösung nicht mit großen Arrays funktioniert. Wenn Sie nach einer besseren und schnelleren Lösung suchen, lesen Sie diese Antwort .
Is erweitert einfach
arr
und übergibt es als Argumente anconcat()
, wodurch alle Arrays zu einem zusammengeführt werden. Es ist gleichbedeutend mit[].concat.apply([], arr)
.Sie können dies auch für eine tiefe Abflachung versuchen:
Siehe Demo auf JSBin .
Referenzen für ECMAScript 6-Elemente, die in dieser Antwort verwendet werden:
Randnotiz: Methoden wie
find()
und Pfeilfunktionen werden nicht von allen Browsern unterstützt, dies bedeutet jedoch nicht, dass Sie diese Funktionen derzeit nicht verwenden können. Verwenden Sie einfach Babel - es wandelt ES6-Code in ES5 um.quelle
apply
auf diese Weise missbraucht werden, habe ich meine Kommentare aus Ihren entfernt. Ich denke immer noch, dass die Verwendungapply
/ Verbreitung auf diese Weise ein schlechter Rat ist, aber da es niemanden interessiert ...const flatten = arr => [].concat(...arr)
Sie können Unterstrich verwenden :
quelle
true
für das zweite Argument angeben .Generische Prozeduren bedeuten, dass wir die Komplexität nicht jedes Mal neu schreiben müssen, wenn wir ein bestimmtes Verhalten verwenden müssen.
concatMap
(oderflatMap
) ist genau das, was wir in dieser Situation brauchen.Voraussicht
Und ja, Sie haben es richtig erraten, es glättet nur eine Ebene, genau so sollte es funktionieren
Stellen Sie sich einen solchen Datensatz vor
Ok, jetzt sagen wir, wir möchten eine Liste drucken, in der alle Spieler aufgeführt sind, die teilnehmen werden
game
.Wenn unsere
flatten
Prozedur auch verschachtelte Arrays reduzieren würde, würden wir dieses Müllergebnis erhalten ...rollt tief, Baby
Das heißt nicht, dass Sie manchmal auch nicht verschachtelte Arrays reduzieren möchten - nur das sollte nicht das Standardverhalten sein.
Wir können
deepFlatten
mit Leichtigkeit ein Verfahren durchführen ...Dort. Jetzt haben Sie für jeden Job ein Werkzeug - eines zum Quetschen einer Verschachtelungsebene
flatten
und eines zum Löschen aller VerschachtelungendeepFlatten
.Vielleicht kannst du es nennen
obliterate
odernuke
wenn dir der Name nicht gefälltdeepFlatten
.Nicht zweimal iterieren!
Natürlich sind die oben genannten Implementierungen clever und prägnant, aber
.map
wenn.reduce
wir einen gefolgt von einem Aufruf von verwenden, bedeutet dies, dass wir tatsächlich mehr Iterationen als nötig durchführenDie Verwendung eines vertrauenswürdigen Kombinators, den ich anrufe,
mapReduce
hilft dabei, die Iterationen auf ein Minimum zu beschränken. Es übernimmt eine Abbildungsfunktionm :: a -> b
, eine Reduktionsfunktionr :: (b,a) ->b
und gibt eine neue Reduktionsfunktion zurück - dieser Kombinator ist das Herzstück der Wandler . Wenn Sie interessiert sind, habe ich andere Antworten darüber geschriebenquelle
concat
selbst sprengt nicht den Stapel, nur...
undapply
tut (zusammen mit sehr großer Arrays). Ich habe es nicht gesehen. Ich fühle mich gerade schrecklich.concat
Javascript eine andere Bedeutung hat als in Haskell. Haskellsconcat
([[a]] -> [a]
) würdeflatten
in Javascript aufgerufen und ist implementiert alsfoldr (++) []
(Javascript:foldr(concat) ([])
Annahme von Curry-Funktionen). Javascriptconcat
ist ein seltsamer Anhang ((++)
in Haskell), der sowohl[a] -> [a] -> [a]
als auch verarbeiten kanna -> [a] -> [a]
.flatMap
, denn genau dasconcatMap
ist: Diebind
Instanz derlist
Monade.concatpMap
wird implementiert alsfoldr ((++) . f) []
. Übersetzt in Javascript :const flatMap = f => foldr(comp(concat) (f)) ([])
. Dies ähnelt natürlich Ihrer Implementierung ohnecomp
.Eine Lösung für den allgemeineren Fall, wenn Sie möglicherweise einige Nicht-Array-Elemente in Ihrem Array haben.
quelle
Object.defineProperty(Array.prototype,'flatten',{value:function(r){for(var a=this,i=0,r=r||[];i<a.length;++i)if(a[i]!=null)a[i] instanceof Array?a[i].flatten(r):r.push(a[i]);return r}});
flattenArrayOfArrays (arr, 10)
oder thisflattenArrayOfArrays(arr, [1,[3]]);
- Diese zweiten Argumente werden der Ausgabe hinzugefügt.r
die Ergebnisse der Rekursion tatsächlich verkettet.Um ein Array von Einzelelement-Arrays zu reduzieren, müssen Sie keine Bibliothek importieren. Eine einfache Schleife ist sowohl die einfachste als auch die effizienteste Lösung:
Für Downvoter: Bitte lesen Sie die Frage, stimmen Sie nicht ab, da sie nicht zu Ihrem ganz anderen Problem passt. Diese Lösung ist sowohl die schnellste als auch die einfachste für die gestellte Frage.
quelle
['foo', ['bar']]
auf['f', 'bar']
.Was ist mit der
reduce(callback[, initialValue])
Methode vonJavaScript 1.8
Würde den Job machen.
quelle
[[1], [2,3]].reduce( (a,b) => a.concat(b), [] )
ist sexy.[[1], [2,3]].reduce( (a,b) => a.concat(b))
Eine weitere ECMAScript 6-Lösung im funktionalen Stil:
Deklarieren Sie eine Funktion:
und benutze es:
Betrachten Sie auch eine native Funktion Array.prototype.flat () (Vorschlag für ES6), die in den letzten Versionen moderner Browser verfügbar ist. Dank an @ (Константин Ван) und @ (Mark Amery) in den Kommentaren erwähnt.
Die
flat
Funktion verfügt über einen Parameter, der die erwartete Tiefe der Array-Verschachtelung angibt, die1
standardmäßig gleich ist.quelle
RangeError: Maximum call stack size exceeded
quelle
Bitte beachten Sie: Wenn
Function.prototype.apply
([].concat.apply([], arrays)
) oder der Spread-Operator ([].concat(...arrays)
) verwendet werden, um ein Array zu reduzieren, können beide Stapelüberläufe für große Arrays verursachen, da jedes Argument einer Funktion auf dem Stapel gespeichert ist.Hier ist eine stapelsichere Implementierung im funktionalen Stil, die die wichtigsten Anforderungen gegeneinander abwägt:
Sobald Sie sich an kleine Pfeilfunktionen in Curryform, Funktionszusammensetzung und Funktionen höherer Ordnung gewöhnt haben, liest sich dieser Code wie Prosa. Die Programmierung besteht dann lediglich darin, kleine Bausteine zusammenzustellen, die immer wie erwartet funktionieren, da sie keine Nebenwirkungen enthalten.
quelle
const flatten = (arr) => arr.reduce((a, b) => a.concat(b), []);
Wenn Sie nur mit gehen, sparen Sie visuellen Müll und erklären Ihren Teamkollegen, warum Sie 3 zusätzliche Funktionen und einige Funktionsaufrufe benötigen .ES6 One Line Flatten
Siehe Lodash-Abflachung , Unterstrich-Abflachung (flach
true
)oder
Getestet mit
ES6 One Line Deep Flatten
Siehe lodash flattenDeep , unterstreichen Sie flatten
Getestet mit
quelle
Array.prototype.concat.apply([], arr)
weil Sie ein zusätzliches Array erstellen, um zurconcat
Funktion zu gelangen . Runtimes können es möglicherweise optimieren oder nicht, wenn sie es ausführen, aber der Zugriff auf die Funktion des Prototyps sieht nicht hässlicher aus, als dies in jedem Fall bereits der Fall ist.Sie können
Array.flat()
mitInfinity
für jede Tiefe des verschachtelten Arrays verwenden.Check hier für die Browser - Kompatibilität
quelle
Ein haskellesker Ansatz
quelle
ES6 Weg:
ES5-
flatten
Funktionsweise mit ES3-Fallback für N-mal verschachtelte Arrays:quelle
Wenn Sie nur Arrays mit 1 Zeichenfolgenelement haben:
wird den Job machen. Bt, das speziell zu Ihrem Codebeispiel passt.
quelle
['$4', ["$6"], ["$12"], ["$25"], ["$25", "$33", ['$45']]].join(',').split(',')
[1,4, [45, 't', ['e3', 6]]].toString().split(',')
---- oder -----[1,4, [45, 't', ['e3', 6], false]].toString().split(',')
(Ich schreibe dies nur als separate Antwort, basierend auf dem Kommentar von @danhbear.)
quelle
Ich empfehle eine platzsparende Generatorfunktion :
Erstellen Sie bei Bedarf ein Array abgeflachter Werte wie folgt:
quelle
...
, um den Generator zu durchlaufen.Ich würde lieber das gesamte Array so wie es ist in einen String umwandeln, aber im Gegensatz zu anderen Antworten würde ich dies mit
JSON.stringify
dertoString()
Methode tun und nicht verwenden , was zu einem unerwünschten Ergebnis führt.Bei dieser
JSON.stringify
Ausgabe müssen nur noch alle Klammern entfernt, das Ergebnis erneut mit Start- und Endklammern umbrochen und das Ergebnis bereitgestellt werden, mitJSON.parse
dem die Zeichenfolge wieder zum "Leben" erweckt wird.quelle
["345", "2", "3,4", "2"]
anstatt jeden dieser Werte zu trennen, um Indizes zu trennen"3,4"
.Sie können auch die neue
Array.Flat()
Methode ausprobieren . Es funktioniert folgendermaßen:Die
flat()
Methode erstellt ein neues Array, in dem alle Subarray-Elemente bis zur Tiefebene 1 rekursiv verkettet sind (dh Arrays innerhalb von Arrays).Wenn Sie auch dreidimensionale oder noch höherdimensionale Arrays reduzieren möchten, rufen Sie die flache Methode einfach mehrmals auf. Zum Beispiel (3 Dimensionen):
Achtung!
Array.Flat()
Methode ist relativ neu. Ältere Browser wie z. B. haben die Methode möglicherweise nicht implementiert. Wenn Sie möchten, dass Ihr Code in allen Browsern funktioniert, müssen Sie Ihren JS möglicherweise auf eine ältere Version übertragen. Suchen Sie nach MD-Webdokumenten für die aktuelle Browserkompatibilität.quelle
Infinity
Argument aufrufen . So:arr.flat(Infinity)
Verwenden des Spread-Operators:
quelle
Das ist nicht schwer, iterieren Sie einfach über die Arrays und führen Sie sie zusammen:
quelle
Es sieht so aus, als wäre dies ein Job für RECURSION!
Code:
Verwendungszweck:
quelle
flatten(new Array(15000).fill([1]))
wirftUncaught RangeError: Maximum call stack size exceeded
und friert meine devTools für 10 Sekunden einIch habe es mit Rekursion und Abschlüssen gemacht
quelle
Ich habe neulich mit ES6-Generatoren rumgespielt und dieses Wesentliche geschrieben . Was beinhaltet...
Grundsätzlich erstelle ich einen Generator, der das ursprüngliche Eingabearray durchläuft. Wenn er ein Array findet, verwendet er den Operatorield * in Kombination mit einer Rekursion, um die internen Arrays kontinuierlich zu reduzieren. Wenn das Element kein Array ist es nur liefert das einzelne Element. Dann reduziere ich den Generator mit dem ES6 Spread-Operator (auch bekannt als Splat-Operator) in eine neue Array-Instanz.
Ich habe die Leistung nicht getestet, aber ich denke, es ist ein schönes einfaches Beispiel für die Verwendung von Generatoren und des Yield * -Operators.
Aber auch hier habe ich nur vermasselt, also bin ich mir sicher, dass es dafür performantere Möglichkeiten gibt.
quelle
einfach die beste lösung ohne lodash
quelle