Angenommen, ich möchte a.x
für jedes Element in summieren arr
.
arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return a.x + b.x})
>> NaN
Ich habe Grund zu der Annahme, dass die Axt irgendwann undefiniert ist.
Das Folgende funktioniert gut
arr = [1,2,4]
arr.reduce(function(a,b){return a + b})
>> 7
Was mache ich im ersten Beispiel falsch?
arr.reduce(function(a,b){return a + b})
im zweiten Beispiel.Antworten:
Nach der ersten Iteration geben Sie eine Zahl zurück und versuchen dann, die Eigenschaft
x
davon zu erhalten, um sie dem nächsten Objekt hinzuzufügen,undefined
und Mathematik mitundefined
Ergebnissen inNaN
.Versuchen Sie, ein Objekt zurückzugeben, das eine
x
Eigenschaft mit der Summe der x-Eigenschaften der Parameter enthält:Erklärung aus Kommentaren hinzugefügt:
Der Rückgabewert jeder Iteration
[].reduce
wird alsa
Variable in der nächsten Iteration verwendet.Iteration 1:
a = {x:1}
,b = {x:2}
,{x: 3}
zugewiesena
in Iteration 2Iteration 2:
a = {x:3}
,b = {x:4}
.Das Problem mit Ihrem Beispiel ist, dass Sie ein Zahlenliteral zurückgeben.
Iteration 1:
a = {x:1}
,b = {x:2}
,// returns 3
wiea
in der nächsten IterationIteration 2 :
a = 3
,b = {x:2}
kehrt zurückNaN
Ein Zahlenliteral
3
hat (normalerweise) keine Eigenschaft, die aufgerufen wird,x
also ist esundefined
und gibtundefined + b.x
zurückNaN
undNaN + <anything>
ist immerNaN
Klarstellung : Ich bevorzuge meine Methode gegenüber der anderen Top-Antwort in diesem Thread, da ich nicht der Meinung bin, dass das Übergeben eines optionalen Parameters zum Reduzieren mit einer magischen Zahl zum Herausholen eines Zahlenprimitivs sauberer ist. Es kann dazu führen, dass weniger Zeilen geschrieben werden, aber imo ist es weniger lesbar.
quelle
Ein sauberer Weg, dies zu erreichen, ist die Angabe eines Anfangswertes:
Wenn die anonyme Funktion zum ersten Mal aufgerufen wird, wird sie mit aufgerufen
(0, {x: 1})
und kehrt zurück0 + 1 = 1
. Das nächste Mal wird es mit aufgerufen(1, {x: 2})
und kehrt zurück1 + 2 = 3
. Es wird dann mit gerufen(3, {x: 4})
und kehrt schließlich zurück7
.quelle
reduce
.TL; DR, stellen Sie den Anfangswert ein
Mit Destrukturierung
arr.reduce( ( sum, { x } ) => sum + x , 0)
Ohne zu zerstören
arr.reduce( ( sum , cur ) => sum + cur.x , 0)
Mit Typoskript
arr.reduce( ( sum, { x } : { x: number } ) => sum + x , 0)
Versuchen wir die Destrukturierungsmethode:
Der Schlüssel dazu ist das Einstellen des Anfangswertes. Der Rückgabewert wird zum ersten Parameter der nächsten Iteration.
Die in der Top-Antwort verwendete Technik ist nicht idiomatisch
Die akzeptierte Antwort schlägt vor, den "optionalen" Wert NICHT zu übergeben. Dies ist falsch, da idiomatisch immer der zweite Parameter enthalten sein muss. Warum? Drei Gründe:
1. Gefährlich - Die Nichtübergabe des Anfangswertes ist gefährlich und kann zu Nebenwirkungen und Mutationen führen, wenn die Rückruffunktion nachlässig ist.
Erblicken
Wenn wir es jedoch so gemacht hätten, mit dem Anfangswert:
Setzen Sie für den Datensatz den ersten Parameter von
Object.assign
auf ein leeres Objekt , es sei denn, Sie möchten das ursprüngliche Objekt mutieren . So :Object.assign({}, a, b, c)
.2 - Bessere Typinferenz - Wenn Sie ein Tool wie Typescript oder einen Editor wie VS Code verwenden, können Sie dem Compiler die Initiale mitteilen, und es kann Fehler abfangen, wenn Sie es falsch machen. Wenn Sie den Anfangswert nicht festlegen, kann er in vielen Situationen möglicherweise nicht erraten werden, und es kann zu gruseligen Laufzeitfehlern kommen.
3 - Respektiere die Funktoren - JavaScript leuchtet am besten, wenn sein inneres funktionales Kind freigesetzt wird. In der Funktionswelt gibt es einen Standard für das "Falten" oder
reduce
ein Array. Wenn Sie das Array falten oder einen Katamorphismus anwenden , verwenden Sie die Werte dieses Arrays, um einen neuen Typ zu erstellen . Sie müssen den resultierenden Typ kommunizieren - Sie sollten dies auch dann tun, wenn der endgültige Typ der der Werte im Array, einem anderen Array oder einem anderen Typ ist.Lassen Sie uns anders darüber nachdenken. In JavaScript können Funktionen wie Daten weitergegeben werden. So funktionieren Rückrufe. Was ist das Ergebnis des folgenden Codes?
[1,2,3].reduce(callback)
Wird es eine Nummer zurückgeben? Ein Objekt? Das macht es klarer
[1,2,3].reduce(callback,0)
Weitere Informationen zur funktionalen Programmierspezifikation finden Sie hier: https://github.com/fantasyland/fantasy-land#foldable
Noch etwas Hintergrund
Die
reduce
Methode akzeptiert zwei Parameter:Die
callback
Funktion akzeptiert die folgenden ParameterFür die erste Iteration
Wenn angegeben
initialItem
,reduce
übergibt die Funktion dasinitialItem
alsaccumulator
und das erste Element des Arrays alsitemInArray
.Falls
initialItem
ist nicht vorgesehen, diereduce
vergeht Funktion auf das erste Element in dem Array alsinitialItem
und dem zweiten Element im Array wieitemInArray
dem Verhalten verwirrend sein kann.Ich unterrichte und empfehle, immer den Anfangswert von Reduzieren einzustellen.
Sie können die Dokumentation unter folgender Adresse einsehen:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Hoffe das hilft!
quelle
Andere haben diese Frage beantwortet, aber ich dachte, ich würde einen anderen Ansatz wählen. Anstatt direkt zur Summierungsaxt zu wechseln, können Sie eine Karte (von Axt zu x) kombinieren und reduzieren (um die x hinzuzufügen):
Zugegeben, es wird wahrscheinlich etwas langsamer sein, aber ich dachte, es lohnt sich, es als Option zu erwähnen.
quelle
Um zu formalisieren, worauf hingewiesen wurde, ist ein Reduzierer ein Katamorphismus, der zwei Argumente verwendet, die zufällig vom gleichen Typ sein können, und einen Typ zurückgibt, der dem ersten Argument entspricht.
Das bedeutet, dass es beim Körper des Reduzierers darum gehen muss,
currentValue
den aktuellen Wert vonaccumulator
in den Wert des neuen umzuwandelnaccumulator
.Dies funktioniert beim Hinzufügen auf einfache Weise, da sowohl der Akkumulator- als auch der Elementwert vom selben Typ sind (aber unterschiedlichen Zwecken dienen).
Das funktioniert nur, weil sie alle Zahlen sind.
Jetzt geben wir dem Aggregator einen Startwert. Der Startwert sollte in den allermeisten Fällen der Typ sein, den Sie vom Aggregator erwarten (der Typ, von dem Sie erwarten, dass er als Endwert herauskommt). Sie sind zwar nicht dazu gezwungen (und sollten es auch nicht sein), aber es ist wichtig, dies zu berücksichtigen.
Sobald Sie das wissen, können Sie sinnvolle Reduzierungen für andere n: 1-Beziehungsprobleme schreiben.
Wiederholte Wörter entfernen:
Angabe einer Anzahl aller gefundenen Wörter:
Reduzieren eines Arrays von Arrays auf ein einzelnes flaches Array:
Jedes Mal, wenn Sie von einer Reihe von Dingen zu einem einzelnen Wert wechseln möchten, der nicht 1: 1 entspricht, sollten Sie eine Reduzierung in Betracht ziehen.
Tatsächlich können sowohl Map als auch Filter als Reduzierungen implementiert werden:
Ich hoffe, dies bietet einen weiteren Kontext für die Verwendung
reduce
.Die einzige Ergänzung, auf die ich noch nicht eingegangen bin, ist die Erwartung, dass die Eingabe- und Ausgabetypen speziell dynamisch sein sollen, da die Array-Elemente Funktionen sind:
quelle
Für die erste Iteration ist 'a' das erste Objekt im Array, daher gibt ax + bx 1 + 2 zurück, dh 3. In der nächsten Iteration wird die zurückgegebene 3 a zugewiesen, also ist a eine Zahl, die jetzt n ax nennt wird NaN geben.
Eine einfache Lösung besteht darin, zuerst die Zahlen im Array abzubilden und sie dann wie folgt zu reduzieren:
Hier
arr.map(a=>a.x)
finden Sie eine Reihe von Zahlen [1,2,4], mit denen.reduce(function(a,b){return a+b})
Sie diese Zahlen jetzt problemlos hinzufügen könnenEine andere einfache Lösung besteht darin, eine Anfangssumme als Null bereitzustellen, indem 'a' wie folgt 0 zugewiesen wird:
quelle
Bei jedem Schritt Ihrer Reduzierung geben Sie kein neues
{x:???}
Objekt zurück. Sie müssen also entweder Folgendes tun:oder du musst tun
quelle
Im ersten Schritt funktioniert es einwandfrei, da der Wert von
a
1 und der vonb
2 ist, aber 2 + 1 zurückgegeben wird und im nächsten Schritt der Wert vonb
der Rückgabewert istfrom step 1 i.e 3
und somitb.x
undefiniert ist. .und undefiniert + anyNumber ist NaN und deshalb erhalten Sie dieses Ergebnis.Stattdessen können Sie dies versuchen, indem Sie den Anfangswert als Null angeben, d. H.
quelle
Wenn Sie ein komplexes Objekt mit vielen Daten haben, wie z. B. ein Array von Objekten, können Sie dies schrittweise lösen.
Zum Beispiel:
Zunächst sollten Sie Ihr Array einem neuen Array von Interesse zuordnen. In diesem Beispiel kann es sich um ein neues Array von Werten handeln.
Diese Rückruffunktion gibt ein neues Array zurück, das nur Werte aus dem ursprünglichen Array enthält, und speichert es in den Werten const. Jetzt ist Ihre Werte const ein Array wie folgt:
Und jetzt sind Sie bereit, Ihre Reduzierung durchzuführen:
Wie Sie sehen können, führt die Reduktionsmethode die Rückruffunktion mehrmals aus. Für jedes Mal wird der aktuelle Wert des Elements im Array genommen und mit dem Akkumulator summiert. Um es richtig zu summieren, müssen Sie den Anfangswert Ihres Akkumulators als zweites Argument der Reduktionsmethode festlegen.
Jetzt haben Sie Ihre neue konstante Summe mit dem Wert 30.
quelle
Reduzierungsfunktion iteriert über eine Sammlung
wird übersetzt in:
Um die Vor- und Nachteile der Funktion "Reduzieren" zu verstehen, sollten Sie sich den Quellcode dieser Funktion ansehen. Die Lodash-Bibliothek verfügt über eine Reduktionsfunktion, die genauso funktioniert wie die "Reduktions" -Funktion in ES6.
Hier ist der Link: Quellcode reduzieren
quelle
um eine Summe aller
x
Requisiten zurückzugeben:quelle
Sie können die Karte verwenden und Funktionen reduzieren
quelle
Die Array-Reduktionsfunktion verwendet drei Parameter, nämlich initialValue (Standard ist 0), Akkumulator und aktueller Wert. Standardmäßig ist der Wert von initialValue "0". welches vom Akku genommen wird
Lassen Sie uns dies im Code sehen.
Jetzt gleiches Beispiel mit Anfangswert:
Gleiches gilt auch für die Objekt-Arrays (die aktuelle Stackoverflow-Frage):
Eine Sache, die man im Kopf behalten sollte, ist InitialValue. Standardmäßig ist 0 und kann alles gegeben werden, was ich meine {}, [] und Nummer
quelle
quelle
Sie sollten keine Axt als Akkumulator verwenden. Stattdessen können Sie Folgendes tun: arr = [{x: 1}, {x: 2}, {x: 4}]
arr.reduce (Funktion (a, b) {a + bx}, 0) `
quelle