Geschrieben von

JavaScript: reduce

WebDev

reduce ist eine Array-Methode in JavaScript, mit der man ein Array in einen einzelnen String umwandeln kann. In diesem Beitrag gehe ich auf die Syntax ein und erkläre die reduce-Methode anhand eines Beispiels.

reduce-Syntax

Die Syntax sieht grob wie folgt aus:

array.reduce(callback, initialValue)

An das Array wird die reduce-Methode angehangen, die 2 Parameter entgegen nimmt:

  • callback: Das ist die Funktion, die auf jedem Wert im Array angewandt wird. Diese Funktion kann 4 Argumente haben. Mehr dazu unten.
  • initialValue: Das ist der Wert, mit dem begonnen werden soll.

Die Callback-Funktion der reduce-Methode kann dann 4 Argumente entgegennehmen:

const callback = (accumulator, currentValue, index, array) => {
  // hier etwas zurückgeben
}

Alternativ kann die Callback-Funktion aus direkt mitgegeben werden:

array.reduce((accumulator, currentValue, index, array) => {
  // hier etwas zurückgeben
}, initialValue)

Was bedeuten die 4 Argumente?

  • accumulator: Für die erste Iteration ist accumulator der Wert von initialValue. Danach nimmt accumulator immer den Wert der letzten Interation ein. accumulator ist eine Pflichtangabe.
  • currentValue: Das ist das aktuell zu verarbeitende Element des Arrays und ist eine Pflichtangabe.
  • index: index wird optional mitgegeben und stellt den Index des aktuellen Array-Elements dar. Wenn initialValue angegeben wurde, dann beginnt index mit dem Index 0, ansonsten mit Index 1.
  • array: Ist das mit reduce aufgerufene Array und gilt als optionale Angabe.

Einfaches reduce-Beispiel

Gehen wir von einem Array mit 3 Zahlen aus:

const numbers = [1, 2, 3]

Aus diesen Zahlen soll nun eine Summe gebildet werden. Mit reduce gelingt das wie folgt:

const total = numbers.reduce((acc, num) => {
  return acc + num
}, 0)
 
console.log(total) // 6

Als Ergebnis erhalten wir 6. Doch was passiert hier konkret? Wir sehen zunächst, dass initialValue auf 0 gesetzt wurde:

Das heißt auch, dass in der ersten Iteration initialValue gleich dem accumulator sein wird:

Gleichzeitig wird currentValue (in diesem Fall num) das erste Element aus dem Array:

Aufgelöst kann man sich den Code dann so vorstellen:

const total = numbers.reduce((0, 1) => {
  return 0 + 1
}, 0)

Das Ergebnis der ersten Iteration ist dann 1. Dieser Wert wird dann der accumulator für die nächste Runde. Gleichzeitig ist das nächste Element aus dem Array der currentValue. Hier wieder aufgelöst:

const total = numbers.reduce((1, 2) => {
  return 1 + 2
}, 0)

Das Ergebnis ist hier 3. Dann gibt es noch ein drittes Element im Array, daher kommt noch eine dritte Iteration hinzu. Das Ergebnis der ersten Iteration wird wieder zum accumulator für die nächste Runde. Gleichzeitig ist das nächste Element aus dem Array der currentValue. Hier wieder aufgelöst:

const total = numbers.reduce((3, 3) => {
  return 3 + 3
}, 0)

Das Ergebnis ist dann 6. Da es keine Elemente mehr im Array gibt, wird nun dieser Wert zurückgegeben.

Weitere reduce-Beispiele

Nachfolgend ein paar weitere Beispiele, wie man recude anwenden kann.

Summieren von Werten in einem Objekt

Gehen wir davon aus, wir haben ein Array mit verschiedenen Farben und möchten zählen wie oft eine Farbe vorkommt. Ausgegeben werden soll ein Objekt. Unser Array sieht wie folgt aus:

const colors = ['green', 'green', 'red', 'red', 'blue', 'black', 'green']

Ergebnis soll sein:

// {
// green: 3,
// red: 2,
// blue: 1,
// black: 1
// }

Da wir also ein Objekt als Ergebnis haben möchte, müssen wir auch ein Objekt als initialValue festsetzen:

const countColors = colors.reduce((acc, color) => {
// Hier kommt die Logik
}, {})

Hier heißt es wieder:

  • In der ersten Iteration wird initialValue gleich dem accumulator sein
  • Gleichzeitig wird currentValue (in diesem Fall color) das erste Element aus dem Array sein.

Wir haben also folgenden Start:

In der ersten Iteration haben wir zunächst ein leeres Objekt {}. Daher wollen wir hier das erste Element aus dem Array (bzw. die erste Farbe) hinzufügen. Gleichzeitig soll für das Element einmal gezählt werden:

const countColors = colors.reduce((acc, color) => {
  return acc[color] = 1
}, {})

Zu Beginn ist der accumulator das Ergebnis der ersten Iteration, also: accumulator: { green: 1 }. Das Argument “color” ist nun das zweite Element aus dem Array: Also wieder “green”. Hier müssen wir also die Anzahl dieser vorkommenden Farbe erhöhen bzw. müssen wir nun hochzählen. Wir müssen also prüfen, ob diese Farbe im Objekt schon existiert. Falls ja, dann soll hochgezählt werden:

const countColors = colors.reduce((acc, color) => {
  if (acc[color]) {
    acc[color] = acc[color] + 1
  } else {
   acc[color] = 1
  }
 
  return acc
}, {})

Hier das Ergebnis:

Geschachteltes Array zu einem flachen Array umwandeln

Schauen wir uns dazu zunächst folgenden Code an:

const array = [
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10] ]

Wir haben hier also 2 Arrays in einem Array. Dabei spricht man auch von einem geschachteltem Array. Nun möchten wir daraus ein flaches Array – also aus mehreren Array nur ein Array – machen. Output soll sein:

// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Da wir also als Output ein Array haben möchten, ist der initialValue ein Array:

const flat = array.reduce((acc, item) => {
// Hier kommt die Logik
}, [])

In der ersten Iteration wird also der accumulator ein leeres Array sein, während item das erste Array sein wird: [1, 2, 3, 4, 5]. Daher sollen diese 2 Werte (einmal leeres Array und einmal das erste Array) miteinander verschmolzen werden. Dazu kann man die concat-Methode benutzen:

const flat = array.reduce((acc, item) => {
  return acc.concat(item)
}, [])

Das Ergebnis ist dann:

Doppelte Werte aus einem Array entfernen

Wenn wir ein Array mit doppelten Werten haben, wie etwa:

let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];

Dann kann man mit der reduce-Methode die Duplikate entfernen:

let result = arr.sort().reduce((accumulator, current) => {
  const length = accumulator.length;
  if (length === 0 || accumulator[length - 1] !== current) {
    accumulator.push(current);
  }
  return accumulator;
}, []);

Ergebnis: