it-swarm.com.de

Was ist der grundlegende Unterschied zwischen Falten und Reduzieren in Kotlin? Wann welche verwenden?

Ich gehe die Grundlagen von Kotlin durch und bin ziemlich verwirrt mit diesen beiden Funktionen fold () und reduction () in Kotlin. Kann mir jemand ein konkretes Beispiel geben, das beide von ihnen unterscheidet?

84
TapanHP

fold nimmt einen Anfangswert an, und der erste Aufruf des Lambdas, das Sie an ihn übergeben, erhält diesen Anfangswert und das erste Element der Auflistung als Parameter.

Nehmen Sie zum Beispiel den folgenden Code, der die Summe einer Liste von ganzen Zahlen berechnet:

listOf(1, 2, 3).fold(0) { sum, element -> sum + element }

Der erste Aufruf des Lambda erfolgt mit den Parametern 0 und 1.

Die Möglichkeit, einen Anfangswert einzugeben, ist hilfreich, wenn Sie einen Standardwert oder -parameter für Ihre Operation angeben müssen. Wenn Sie beispielsweise nach dem Maximalwert in einer Liste suchen, aber aus irgendeinem Grund mindestens 10 zurückgeben möchten, können Sie Folgendes tun:

listOf(1, 6, 4).fold(10) { max, element ->
    if (element > max) element else max
}

reduce nimmt keinen Anfangswert an, sondern beginnt mit dem ersten Element der Sammlung als Akkumulator (im folgenden Beispiel sum genannt).

Lassen Sie uns zum Beispiel noch einmal eine Summe von ganzen Zahlen machen:

listOf(1, 2, 3).reduce { sum, element -> sum + element }

Der erste Aufruf des Lambda erfolgt hier mit den Parametern 1 und 2.

Sie können reduce verwenden, wenn Ihre Operation von keinen anderen Werten als denen in der Sammlung abhängt, auf die Sie sie anwenden.

182
zsmb13

Der wichtigste funktionale Unterschied, den ich nennen würde (der in den Kommentaren zu der anderen Antwort erwähnt wird, aber möglicherweise schwer zu verstehen ist), ist, dass reduceeine Ausnahme auslöst, wenn er an einem ausgeführt wird leere Sammlung.

listOf<Int>().reduce { x, y -> x + y }
// Java.lang.UnsupportedOperationException: Empty collection can't be reduced.

Das ist weil .reduce weiß nicht, welcher Wert bei "Keine Daten" zurückgegeben werden soll.

Vergleichen Sie dies mit .fold, für das Sie einen "Startwert" angeben müssen, der im Falle einer leeren Sammlung der Standardwert ist:

val result = listOf<Int>().fold(0) { x, y -> x + y }
assertEquals(0, result)

Also, auch wenn Sie Ihre Sammlung nicht zu einem einzigen Element eines anderen (nicht verwandten) Typs zusammenfassen möchten (der nur .fold können Sie tun), wenn Ihre anfängliche Sammlung leer sein kann, müssen Sie entweder zuerst Ihre Sammlungsgröße überprüfen und dann .reduce, oder benutze einfach .fold

val collection: List<Int> = // collection of unknown size

val result1 = if (collection.isEmpty()) 0
              else collection.reduce { x, y -> x + y }

val result2 = collection.fold(0) { x, y -> x + y }

assertEquals(result1, result2)
3
Matt Klein