Fold ou Reduce en Kotlin : la question éternelle des débutants
\n\nSi vous programmez en Kotlin depuis au moins une semaine, vous avez sûrement déjà rencontré les fonctions fold et reduce. À première vue, elles font la même chose : parcourir une collection et accumuler un résultat. Mais le diable, comme toujours, se cache dans les détails. Un mauvais choix peut entraîner des bugs, des exceptions ou simplement un code peu élégant.
Dans cet article, nous allons analyser la différence entre fold et reduce en Kotlin, observer des exemples concrets issus de projets réels et mémoriser une fois pour toutes quelle fonction utiliser. C'est parti !
\n\nQue sont fold et reduce ? Compréhension de base
\n\nLes deux fonctions sont des opérations terminales pour les collections. Elles prennent tous les éléments et les réduisent à une seule valeur. Imaginez que vous ayez une pile de crêpes et que vous vouliez obtenir un grand burger. fold et reduce sont deux techniques différentes pour les empiler.
Reduce : une approche minimaliste
\n\nLa fonction reduce utilise le premier élément de la collection comme valeur initiale de l'accumulateur. Cela signifie qu'elle ne peut tout simplement pas fonctionner avec une collection vide — elle lèvera une UnsupportedOperationException.
val numbers = listOf(1, 2, 3, 4, 5)\nval sum = numbers.reduce { acc, i -> acc + i }\nprintln(sum) // 15\n\nIci, acc est initialement égal à 1 (le premier élément), puis on y ajoute 2, puis 3, et ainsi de suite. Simple et élégant, mais il y a un détail.
Fold : le contrôle du début
\n\nfold, contrairement à reduce, nécessite de spécifier explicitement une valeur initiale. Cela vous donne un contrôle total et, plus important encore, permet de travailler avec des collections vides.
val numbers = listOf(1, 2, 3, 4, 5)\nval sum = numbers.fold(0) { acc, i -> acc + i }\nprintln(sum) // 15\n\nval emptyList = listOf<Int>()\nval emptySum = emptyList.fold(0) { acc, i -> acc + i }\nprintln(emptySum) // 0, aucune erreur !\n\nVous voyez la différence ? fold renvoie la valeur initiale si la collection est vide. reduce échouerait dans une telle situation.
Différences clés entre fold et reduce en Kotlin
\n\nOrganisons ces connaissances. Voici un tableau qui vous aidera à vous repérer rapidement :
\n\n- \n
- Valeur initiale : Dans
fold, vous la définissez vous-même. Dansreduce, c'est le premier élément de la collection. \n - Type du résultat : Dans
fold, le type du résultat peut être différent du type des éléments (par exemple, additionner des Int pour obtenir une String). Dansreduce, le type du résultat correspond toujours au type des éléments. \n - Collection vide :
foldla gère correctement (renvoie la valeur initiale).reducelève une exception. \n - Performance : Les deux fonctions s'exécutent en O(n). La différence de performance est négligeable. \n
Voyons maintenant cela dans le code.
\n\nExemple 1 : Types différents de l'accumulateur et des éléments
\n\nSupposons que nous ayons une liste de nombres et que nous voulions obtenir une chaîne de caractères — leur somme sous une forme lisible. fold s'en sort parfaitement, car le type de l'accumulateur (String) est différent du type des éléments (Int).
val numbers = listOf(1, 2, 3)\nval result = numbers.fold("Somme : ") { acc, i -> "$acc$i " }\nprintln(result) // "Somme : 1 2 3 "\n\nEssayez de faire la même chose avec reduce — le compilateur générera une erreur, car reduce exige que le type de l'accumulateur corresponde au type des éléments.
Exemple 2 : Calcul de la somme avec une valeur initiale
\n\nUne tâche courante : calculer le montant total des commandes, mais nous avons déjà un solde initial sur le compte.
\n\nval orders = listOf(100, 250, 75)\nval initialBalance = 500\nval totalBalance = orders.fold(initialBa