[ad_1]

Découvrez la version de defaultDict de Kotlin

Une carte du monde

Nous savons tous ce qu’est une (hash)map et si vous connaissez le langage de programmation Python, vous êtes probablement tombé sur defaultdictà un moment donné. Je me demandais si la même construction est disponible dans Kotlin et j’expliquerai ma découverte dans cet article.

La documentation de Python defaultdict y compris quelques exemples peuvent être trouvés ici. Son utilisation de base est démontrée dans l’extrait suivant :

Le dict par défaut tire son nom du fait qu’il inclut des valeurs par défaut pour les clés qu’il ne connaît pas encore. Comme dans l’exemple ci-dessus où un client essaie de prendre une valeur aléatoire de la carte qui se traduit par une valeur 0bien qu’il n’y ait jamais rien écrit sur cette carte.

La defaultdict peut également être utilisé avec d’autres types que des entiers et s’assure que vous n’obtenez pas de KeyError sur les accès clés inconnus. Au lieu de cela, il fournit une valeur par défaut pour les clés inconnues, ce qui peut être très utile pour regrouper et compter des algorithmes comme celui-ci :

Ce petit outil peut être extrêmement utile et c’est quelque chose que j’ai beaucoup utilisé lors de la résolution de problèmes algorithmiques que vous rencontrez dans de très nombreuses situations d’entretien technique sur lesquelles j’ai écrit ici.

Considérons maintenant le langage de programmation Kotlin et voyons si nous pouvons avoir le même comportement qu’avec Python defaultdict.

Supposons que l’on veuille écrire une fonction générique qui prend une collection et renvoie une carte contenant les éléments de la collection d’origine associés au nombre de leurs occurrences :

Bien qu’il existe un moyen fonctionnel naturel de le faire dans Kotlin, nous souhaitons d’abord envisager certaines approches itératives. Commençons par le suivant.

Nous pouvons utiliser un MutableMap pour cet algorithme. Lors de l’itération sur toutes les valeurs, nous examinons la carte pour voir si elle a déjà été vue. Si c’est le cas, nous incrémentons le compteur ; sinon, nous mettons un décompte initial de 1 dans la carte. Voyons comment nous pouvons faire mieux en utilisant des valeurs par défaut explicites.

Comme alternative à la solution précédente, nous pouvons utiliser putIfAbsent pour s’assurer que l’élément est initialisé avec 0 afin que nous puissions incrémenter en toute sécurité le compteur dans la ligne suivante. Dans ce cas, nous fournissons une valeur par défaut explicite. Un autre outil, bien que similaire, est getOrDefault:

countMap[e] = countMap.getOrDefault(e, 0) + 1

Fournir des valeurs par défaut explicites via putIfAbsent ou getOrDefault conduit à des solutions faciles et compréhensibles, mais nous pouvons faire mieux.

Semblable à Python defaultdictKotlin est livré avec un joli extension appelé MutableMap::withDefault et ça ressemble à ça :

Cette extension permet de fournir un initialiseur pour les clés qui n’ont pas de valeur associée dans la carte. Utilisons-le dans notre solution :

Cela simplifie davantage le code puisque nous n’avons plus besoin de traiter les valeurs inconnues dans l’itération. Puisque nous utilisons une carte par défaut, nous pouvons en tirer des valeurs en toute sécurité et incrémenter le compteur au fur et à mesure.

Note importante

Il y a une chose importante dont vous devez être conscient lorsque vous utilisez le withDefault extension, qui fait partie de sa documentation :

[…] Cette valeur par défaut implicite est utilisée lorsque la carte d’origine ne contient pas de valeur pour la clé spécifiée et qu’une valeur est obtenu avec [Map.getValue] fonction […]

La valeur par défaut ne sera fournie que si vous utilisez Map::getValuece qui n’est pas le cas lors de l’accès à la carte avec des opérateurs d’index.

La raison en est le contrat de Map interface, qui dit :

Renvoie la valeur correspondant à la donnée [key]ou null si une telle clé n’est pas présente dans la carte.

Étant donné que les cartes par défaut veulent remplir ce contrat, elles ne peuvent rien renvoyer d’autre que null dans le cas de clés inexistantes, ce qui a été discuté dans le Forum Kotlin avant de.

Très bien, nous avons vu que Kotlin propose en effet des moyens de fournir des valeurs par défaut dans les cartes, ce qui est formidable. Mais est-il de toute façon idiomatique d’écrire du code comme nous l’avons fait dans les exemples ci-dessus ? En fait ça dépend. La plupart des cas peuvent être résolus de manière beaucoup plus simple en utilisant les API fonctionnelles de Kotlin qui sont livrées avec des fonctionnalités intégrées de regroupement et de comptage.

Néanmoins, il est bon de connaître les alternatives car, dans certaines situations, vous pouvez choisir d’opter pour une approche itérative. Cela est particulièrement vrai si vous visez la solution la plus optimale, en termes de temps et d’espace. Permettez-moi de vous fournir une version simplifiée de notre code :

Il utilise toujours un explicite for boucle mais a été simplifiée par l’utilisation de apply ce qui nous permet d’initialiser la carte en une seule instruction. Vous pouvez lire sur apply et toutes les autres fonctions d’étendue ici.

Il existe des dizaines de façons de résoudre le problème donné dans Kotlin, mais probablement la plus courte (mais pas la plus optimale) est une approche fonctionnelle :

Nous pouvons résoudre des algorithmes simples de différentes manières en utilisant Kotlin. Semblable à Python, vous pouvez initialiser une carte avec un fournisseur de valeur par défaut, mais vous devez être conscient que l’accès normal à l’opération d’indexation ne fonctionnera pas comme prévu.

Comme documenté, le getValue la fonction doit être utilisée à la place. Étant donné que Kotlin est livré avec une bibliothèque standard très utile, vous souhaitez envisager de l’utiliser autant que possible. Cela signifie que l’implémentation d’éléments courants tels que le regroupement ou le comptage ne doit, dans la plupart des cas, pas être implémentée à partir de rien, mais plutôt avec les fonctionnalités existantes de la bibliothèque standard.

D’autre part, si vous visez des solutions optimales, par exemple lors d’un entretien de codage, il est important de comprendre les alternatives aux approches fonctionnelles qui peuvent rendre difficile l’évaluation des complexités temporelles et spatiales. Savoir utiliser une carte par défaut est un élément important pour écrire un code compréhensible et performant.

[ad_2]

Télécharger ici

Leave a Reply

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Instagram

Ce message d’erreur n’est visible que pour les administrateurs de WordPress

Erreur. Aucun flux trouvé.

Veuillez aller sur la page de réglages d‘Instagram Feed pour connecter votre compte.