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 0und 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
}
reducenimmt keinen Anfangswert an, sondern beginnt mit dem ersten Element der Sammlung als Akkumulator ( sumim 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 1und 2.
Sie können verwenden, reducewenn 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, .reducedass 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 .foldmöglich ist), müssen Sie entweder Ihre Sammlung überprüfen, wenn Ihre Startsammlung möglicherweise leer ist Größe zuerst und dann .reduceoder 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)