T: / Corrigés des challenges / Java
Utilisation et présentation de la classe HashMap en Java : initialisation et méthodes clés.
Sixième corrigé des challenges de l’histoire originale Greenoïd, créée à l’occasion de la Battle Dev Thales 2024.
Il était question dans ce challenge d’analyser les flux dans un réseau de vannes pour déterminer la vanne qui recevait le plus d’eau à la fin du réseau. Il y avait 4 niveaux successifs de vannes, de 1 à 4. En partant des débits des vannes 1 et de la définition des différents écoulements, il fallait donc trouver la vanne de niveau 4 qui recevait le plus d’eau.
Plusieurs solutions étaient possibles pour résoudre ce challenge.
Parmi les solutions complexes, on pouvait travailler avec de la récursivité ou créer des objets pour gérer les différents noeuds. Mais… en analysant bien le problème, on pouvait simplifier davantage l’algorithme à mettre en oeuvre.
Pour illustrer cet algorithme, on va résoudre le challenge en Java ! En utilisant la classe HashMap issue de la collection java.util.
Au programme :
Dans la méthode main, juste après le jeu de données, on peut créer la HashMap :
// == Création d'une HashMap pour stocker les débits de chaque vanne
HashMap<String, Integer> debitParVanne = new HashMap<>();
Lorsqu’on crée une HashMap, on définit le type de la clé (ici String) et le type des valeurs contenues (ici Integer). Ces types devront être scrupuleusement respectés au risque de déclencher des erreurs.
Ici, une clé représentera le nom de la vanne : « V1A », « V2C », etc.
Et une valeur représentera son débit : 1560, 887, etc.
Les premières informations utiles du challenge se trouvaient dans la variable flux qui contenait les débits des vannes de niveau 1. On pouvait donc parcourir flux, extraire les données intéressantes avec un peu de parsing et initialiser notre HashMap avec de premières valeurs :
// == Initialisation des débits de départ pour les vannes de niveau 1
for (String fluxVanne : flux) {
String[] parts = fluxVanne.split(":"); // Divise une seule fois la chaîne
String vanne = parts[0]; // Extraction du code de la vanne (ex : "V1A")
int debitInitial = Integer.parseInt(parts[1]); // Extraction du débit initial (ex : 2621)
debitParVanne.put(vanne, debitInitial);
}
Un peu d’explications :
Maintenant il s’agit de parcourir tout le réseau pour suivre les débits de chaque vanne.
// == Répartition des débits dans le réseau
for (String connexion : network) {
String[] parts = connexion.split(":"); // Divise la chaîne une seule fois
String vanneParent = parts[0]; // Extraction du code de la vanne parent (ex : "V1A")
int debitParent = debitParVanne.getOrDefault(vanneParent, 0); // Récupération du débit de la vanne parent
// Vannes enfants recevant de l'eau de la vanne parent
String[] vannesEnfants = parts[1].split(","); // Séparation des vannes enfants
// Distribution équitable du débit du parent vers chaque vanne enfant
int debitDistribue = debitParent / vannesEnfants.length;
for (String vanneEnfant : vannesEnfants) {
// On ajoute le débit distribué à chaque vanne enfant
debitParVanne.put(
vanneEnfant,
debitParVanne.getOrDefault(vanneEnfant, 0) + debitDistribue);
}
}
Un peu d’explications :
Pour cela, on met en place un algorithme classique de recherche de maximum :
// == Recherche des vannes de niveau 4 avec le débit maximal
int debitMax = 0;
String vannesMax = "";
for (Map.Entry<String, Integer> entree : debitParVanne.entrySet()) {
String vanne = entree.getKey();
int debit = entree.getValue();
// Filtrer pour ne garder que les vannes de niveau 4
if (vanne.charAt(1) == '4') {
if (debit > debitMax) {
// Mise à jour du débit maximal et réinitialisation de la chaîne des vannes avec ce débit
debitMax = debit;
vannesMax = vanne;
} else if (debit == debitMax) {
// Ajout de la vanne en cas d'égalité de débit
vannesMax += vanne;
}
}
}
Un peu d’explications :
Il ne reste plus qu’à afficher le résultat :
System.out.println(debitMax + "_" + vannesMax);
Initialisation d’une HashMap
HashMap<K, V> map = new HashMap<>();
K est le type de la clé. V est le type de la valeur.
Ajout d’un élément dans une HashMap
debitParVanne.put("V1A", 1245);
On utilise la méthode put(), la clé en premier, la valeur ensuite. Si la clé existe déjà, la valeur est mise à jour.
Accès à un élément dans une HashMap
int debit = debitParVanne.get("V1A");
On utilise la méthode get(). Si la clé n’existe pas, get retourne null.
Comme vu dans le corrigé, il y a aussi la méthode getOrDefault() qui permet de retourner une valeur définie si la clé n’existe pas.
Supprimer un élément dans une HashMap
debitParVanne.remove("V1A");
On utilise la méthode remove(). Si la clé n’existe pas, rien ne se passe, aucune erreur n’est générée.
Vérifier la présence d’un élément dans une HashMap
if (debitParVanne.containsKey("V1A")) {} // Vérification de l'existence d'une clé
if (debitParVanne.containsValue(1245)) {} // Vérification de l'existence d'une valeur
2 méthodes containsKey ou containsValue selon ce qu’on cherche à vérifier.
Parcourir les éléments d’une HashMap
for (String key : debitParVanne.keySet()) {} // On parcourt seulement les clés
for (Integer value : debitParVanne.values()) {} // On parcourt seulement les valeurs
for (Map.Entry<String, Integer> entry : debitParVanne.entrySet()) { // On parcourt les deux à la fois
On a vu dans le corrigé la dernière méthode permettant de tout parcourir à la fois mais on peut aussi parcourir seulement les valeurs ou seulement les clés !
Récupérer la taille d’une HashMap
int nbVannes = debitParVanne.size();
Il en existe encore d’autres mais pour une premier tour d’horizon c’est pas mal !
Et voici le code complet de résolution du challenge, en java, en mettant bout à bout toutes les portions de code décrites jusqu’ici : (avec un jeu de données aléatoire)
import java.util.*;
import java.io.*;
import java.math.*;
public class Challenge
{
public static void main(String[] args)
{
//== NE PAS TOUCHER
String[] flux = {"V1A:2226", "V1B:2975", "V1C:2382"};
String[] network = {"V1A:V2A,V2C,V2D", "V1B:V2A,V2D", "V1C:V2B,V2C,V2A", "V2A:V3G,V3D,V3E", "V2B:V3C,V3E,V3D,V3G,V3B", "V2C:V3F,V3G,V3E,V3D,V3A", "V2D:V3F,V3C,V3D,V3A,V3G", "V3A:V4I,V4K,V4L,V4E", "V3B:V4F,V4E,V4A,V4I,V4J", "V3C:V4I,V4L,V4B,V4C", "V3D:V4F,V4H,V4G,V4D,V4I", "V3E:V4E,V4A,V4H,V4K", "V3F:V4G,V4E,V4B,V4H,V4D", "V3G:V4K,V4J,V4I,V4G,V4C,V4H"};
//== NE PAS TOUCHER
// == Création d'une HashMap pour stocker les débits de chaque vanne
HashMap<String, Integer> debitParVanne = new HashMap<>();
// == Initialisation des débits de départ pour les vannes de niveau 1
for (String fluxVanne : flux) {
String[] parts = fluxVanne.split(":"); // Divise une seule fois la chaîne
String vanne = parts[0]; // Extraction du code de la vanne (ex : "V1A")
int debitInitial = Integer.parseInt(parts[1]); // Extraction du débit initial (ex : 2621)
debitParVanne.put(vanne, debitInitial);
}
// == Répartition des débits dans le réseau
for (String connexion : network) {
String[] parts = connexion.split(":"); // Divise la chaîne une seule fois
String vanneParent = parts[0]; // Extraction du code de la vanne parent (ex : "V1A")
int debitParent = debitParVanne.getOrDefault(vanneParent, 0); // Récupération du débit de la vanne parent
// Vannes enfants recevant de l'eau de la vanne parent
String[] vannesEnfants = parts[1].split(","); // Séparation des vannes enfants
// Distribution équitable du débit du parent vers chaque vanne enfant
int debitDistribue = debitParent / vannesEnfants.length;
for (String vanneEnfant : vannesEnfants) {
// On ajoute le débit distribué à chaque vanne enfant
debitParVanne.put(
vanneEnfant,
debitParVanne.getOrDefault(vanneEnfant, 0) + debitDistribue
);
}
}
// == Recherche des vannes de niveau 4 avec le débit maximal
int debitMax = 0;
String vannesMax = "";
for (Map.Entry<String, Integer> entree : debitParVanne.entrySet()) {
String vanne = entree.getKey();
int debit = entree.getValue();
// Filtrer pour ne garder que les vannes de niveau 4
if (vanne.charAt(1) == '4') {
if (debit > debitMax) {
// Mise à jour du débit maximal et réinitialisation de la chaîne des vannes avec ce débit
debitMax = debit;
vannesMax = vanne;
} else if (debit == debitMax) {
// Ajout de la vanne en cas d'égalité de débit
vannesMax += vanne;
}
}
}
System.out.println(debitMax + "_" + vannesMax);
}
}
Other content to discover