155 votes

Quelle est la différence fondamentale entre fold et réduire en Kotlin? Quand utiliser lequel?

Je passe en revue les bases de Kotlin et je suis assez confus avec cette fonction fold () et reduction () dans Kotlin. Quelqu'un peut-il me donner un exemple concret qui les distingue?

328voto

zsmb13 Points 36441

fold prend une valeur initiale, et la première invocation de la lambda de passer, il va recevoir la valeur initiale et le premier élément de la collection en tant que paramètres.

Prenez, par exemple, le code suivant qui calcule la somme d'une liste d'entiers:

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

Le premier appel à la lambda sera avec les paramètres 0 et 1.

Avoir la capacité de transmettre en une valeur initiale est utile si vous avez à fournir une sorte de valeur par défaut ou d'un paramètre de votre opération. Par exemple, si vous avez été la recherche de la valeur maximale à l'intérieur d'une liste, mais pour une raison quelconque veux retourner au moins de 10, vous pouvez effectuer les opérations suivantes:

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

reduce ne pas prendre une valeur initiale, mais au lieu de cela commence avec le premier élément de la collection que l'accumulateur (appelés sum dans l'exemple suivant).

Par exemple, prenons-en une somme d'entiers de nouveau:

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

Le premier appel à la lambda ici seront, avec les paramètres 1 et 2.

Vous pouvez utiliser reduce lors de votre opération ne dépend pas des valeurs autres que celles de la collection que vous postulez pour.

14voto

Matt Klein Points 809

La différence fonctionnelle majeure, je l'appellerais " (ce qui est mentionné dans les commentaires sur l'autre réponse, mais peut être difficile à comprendre) c'est que l' reduce va lever une exception si elle est effectuée sur une zone vide de la collection.

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

C'est parce qu' .reduce ne sait pas quelle est la valeur de retour en cas de "pas de données".

Cela contraste avec .fold, ce qui vous oblige à fournir une "valeur de départ", qui sera la valeur par défaut en cas de vide de la collection:

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

Donc, même si vous ne voulez pas à s'agréger votre collection sur un seul élément d'un autre (non-relié) type (qui n' .fold vous permettra de le faire), si votre départ de la collection peut être vide, alors vous devez vérifier votre taille de la collection en premier et ensuite .reduce, ou simplement l'utiliser .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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X