flatMap
ist unglaublich nützlich für Sammlungen, aber Javascript bietet keine, während Sie haben Array.prototype.map
. Warum?
Gibt es eine Möglichkeit, flatMap
Javascript auf einfache und effiziente Weise zu emulieren , ohne es flatMap
manuell zu definieren ?
javascript
functional-programming
Sergey Alaev
quelle
quelle
arr.reduce((arr, v) => (arr.push(...v), arr), [])
?arr.map(...).reduce(...)
)..map
gepingt haben.Antworten:
Update:
Array.prototype.flatMap
ist auf dem Weg zu nativem ECMAScript. Es ist derzeit in Phase 4 .Es wird in vielen Umgebungen weitgehend unterstützt. Überprüfen Sie anhand dieses Snippets, ob es in Ihrem Browser funktioniert.
const data = [ 1, 2, 3, 4 ] console.log(data.flatMap(x => Array(x).fill(x))) // [ 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 ]
Weil Programmieren keine Magie ist und nicht jede Sprache Funktionen / Grundelemente hat, die jede andere Sprache hat
Was zählt, ist
Mit JavaScript können Sie es selbst definieren
const concat = (x,y) => x.concat(y) const flatMap = (f,xs) => xs.map(f).reduce(concat, []) const xs = [1,2,3] console.log(flatMap(x => [x-1, x, x+1], xs))
Oder ein Umschreiben, bei dem die beiden Schleifen zu einer zusammengefasst werden
const flatMap = (f,xs) => xs.reduce((acc,x) => acc.concat(f(x)), []) const xs = [1,2,3] console.log(flatMap(x => [x-1, x, x+1], xs))
Wenn Sie es auf der wollen
Array.prototype
, hält Sie nichts aufconst concat = (x, y) => x.concat(y) const flatMap = (f, xs) => xs.map(f).reduce(concat, []) if (Array.prototype.flatMap === undefined) { Array.prototype.flatMap = function(f) { return flatMap(f, this) } } const xs = [1, 2, 3] console.log(xs.flatMap(x => [x-1, x, x+1]))
.as-console-wrapper { top: 0; max-height: 100% !important; }
quelle
Array.prototype._mylib_flatMap
) mit einem Namespace zu versehen oder sogar ES6-Symbole zu verwenden, anstatt sie einfach zu definierenArray.prototype.flatMap
.map
definierter globaler Funktion vor! Zweitens ist nur schlechte Übungappend
,map
,filter
,foldl
,foldr
unter unzählig anderen in dem Standard - Namespace. Es macht es nicht zu einer schlechten Praxis, weil Sie jemanden sagen hörten "Globale sind schlecht" oder "Eingeborene zu erweitern ist schlecht" - Schläger gehört zu den am besten gestalteten Sprachen. Sie wissen einfach nicht, wie / wann Sie es richtig machen sollen.flatMap
wurde vom TC39 als Teil von ES2019 (ES10) genehmigt. Sie können es so verwenden:[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]
Hier ist meine eigene Implementierung der Methode:
const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])
MDN Artikel auf flatMap
quelle
flapMap
? Ich möchte meine Karte platt machen, nicht klappen!const flatMap = (arr, ...args) => [].concat(...arr.map(...args));
(oderapply
wenn Sie den Spread-Operator nicht verwenden können) - obwohl diese concat-Version Probleme mit der Größe des Aufrufstapels für große Arrays aufweist, wie in einer niedrigeren Lösung erwähntIch weiß, dass Sie gesagt haben, Sie wollten es nicht selbst definieren, aber diese Implementierung ist eine ziemlich triviale Definition.
Es gibt auch das von derselben Github-Seite:
Hier ist ein etwas kürzerer Weg mit es6-Spread, ähnlich wie bei renaudtertrais - aber mit es6 und ohne Hinzufügen zum Prototyp.
var flatMap = (a, cb) => [].concat(...a.map(cb)) const s = (v) => v.split(',') const arr = ['cat,dog', 'fish,bird'] flatMap(arr, s)
Würde einer dieser beiden helfen?
Es sollte beachtet werden (dank @ftor), dass diese letztere "Lösung" unter "Maximale Größe des Aufrufstapels überschritten" leidet, wenn sie auf einem wirklich großen Array (z. B. 300.000 Elementen) aufgerufen wird
a
.quelle
[].concat(...(new Array(300000).fill("foo").map(x => x.toUpperCase())))
. Sicher, es ist ein Eckfall. Aber du solltest es zumindest erwähnen.Lodash bietet eine Flatmap-Funktion, die für mich praktisch gleichbedeutend ist mit Javascript, das sie nativ bereitstellt. Wenn Sie kein Lodash-Benutzer sind,
Array.reduce()
kann die Methode von ES6 das gleiche Ergebnis liefern, Sie müssen jedoch in diskreten Schritten abbilden und dann reduzieren.Unten finden Sie ein Beispiel für jede Methode, bei der eine Liste von Ganzzahlen zugeordnet und nur die Gewinnchancen zurückgegeben werden.
Lodash:
_.flatMap([1,2,3,4,5], i => i%2 !== 0 ? [i] : [])
ES6 Reduzieren:
[1,2,3,4,5].map(i => i%2 !== 0 ? [i] : []).reduce( (a,b) => a.concat(b), [] )
quelle
Ein ziemlich prägnanter Ansatz besteht darin, Folgendes zu verwenden
Array#concat.apply
:const flatMap = (arr, f) => [].concat.apply([], arr.map(f)) console.log(flatMap([1, 2, 3], el => [el, el * el]));
quelle
Ich habe so etwas gemacht:
Array.prototype.flatMap = function(selector){ return this.reduce((prev, next) => (/*first*/ selector(prev) || /*all after first*/ prev).concat(selector(next))) }
[[1,2,3],[4,5,6],[7,8,9]].flatMap(i => i); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
[{subarr:[1,2,3]},{subarr:[4,5,6]},{subarr:[7,8,9]}].flatMap(i => i.subarr); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
quelle
Wir haben jetzt eine
flatMap()
in Javascript! Und es wird ziemlich gut unterstütztconst dublicate = x => [x, x]; console.log([1, 2, 3].flatMap(dublicate))
quelle
{ "message": "Uncaught TypeError: [1,2,3].flatMap is not a function", "filename": "https://stacksnippets.net/js", "lineno": 15, "colno": 23 }
Array.prototype.flatMap()
ist jetzt in JS angekommen. Möglicherweise unterstützen jedoch nicht alle Browser die Überprüfung der aktuellen Browserkompatibilität der Mozilla-Webdokumente .Was zum
flatMap()
Methode ordnet zunächst jedes Element mithilfe einer Rückruffunktion als Argument zu und glättet dann das Ergebnis in ein neues Array (das 2d-Array ist jetzt 1d, da die Elemente abgeflacht sind).Hier ist auch ein Beispiel für die Verwendung der Funktion:
let arr = [[2], [4], [6], [8]] let newArr = arr.flatMap(x => [x * 2]); console.log(newArr);
quelle