Ich bin ziemlich verwirrt mit diesen beiden Funktionen fold()
und reduce()
kann mir in Kotlin jemand ein konkretes Beispiel geben, das beide unterscheidet?
Ich bin ziemlich verwirrt mit diesen beiden Funktionen fold()
und reduce()
kann mir in Kotlin jemand ein konkretes Beispiel geben, das beide unterscheidet?
Antworten:
fold
Nimmt einen Anfangswert und der erste Aufruf des Lambdas, das Sie an ihn übergeben, erhält diesen Anfangswert und das erste Element der Sammlung 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 zu übergeben, ist nützlich, 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 ( sum
im folgenden Beispiel aufgerufen ).
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 verwenden, reduce
wenn Ihre Operation nicht von anderen Werten als denen in der Sammlung abhängt, auf die Sie sie anwenden.
emptyList<Int>().reduce { acc, s -> acc + s }
erzeugt eine Ausnahme, ist aber emptyList<Int>().fold(0) { acc, s -> acc + s }
in Ordnung.
listOf<Int>(1, 2).reduce { acc: Number, i: Int -> acc.toLong() + i }
(der Listentyp ist Int, während der Akkumulatortyp als Number deklariert ist und tatsächlich ein Long ist)
Der Hauptfunktionsunterschied, den ich hervorheben würde (der in den Kommentaren zur anderen Antwort erwähnt wird, aber möglicherweise schwer zu verstehen ist), besteht darin, dass reduce
eine Ausnahme ausgelöst wird, wenn er für eine leere Sammlung ausgeführt wird.
listOf<Int>().reduce { x, y -> x + y }
// java.lang.UnsupportedOperationException: Empty collection can't be reduced.
Dies liegt daran, .reduce
dass nicht bekannt ist, welcher Wert bei "keine Daten" zurückgegeben werden soll.
Vergleichen Sie dies damit .fold
, dass 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)
Selbst wenn Sie Ihre Sammlung nicht zu einem einzigen Element eines anderen (nicht verwandten) Typs zusammenfassen möchten (was nur .fold
möglich ist), müssen Sie entweder Ihre Sammlung überprüfen, wenn Ihre Startsammlung möglicherweise leer ist Größe zuerst und dann .reduce
oder einfach verwenden.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)