Comparateur, tri des collections - 1

« Salut Amigo ! »

"Salut, Bilaabo !"

« Aujourd'hui, nous allons examiner un petit sujet, mais intéressant et utile : le tri des collections. »

"Le tri ? J'en ai entendu parler."

"Il y a longtemps, chaque programmeur devait être capable d'écrire des algorithmes de tri. Il pouvait et devait les écrire. Mais cette époque est révolue. Aujourd'hui, écrire son propre code de tri est considéré comme une mauvaise forme, tout comme réécrire tout ce qui a déjà été inventé."

"En Java (et dans d'autres langages de programmation), le tri est déjà implémenté.  Votre tâche est d'apprendre à utiliser correctement ce qui existe déjà. "

"D'ACCORD."

"La classe d'assistance Collections a une méthode de tri statique qui est utilisée pour trier les collections, ou plus précisément les listes. Les éléments des cartes et des ensembles n'ont pas d'ordre/d'index, il n'y a donc rien à trier."

"Oui, je me souviens. J'ai utilisé cette méthode une fois pour trier une liste de nombres."

"Génial. Mais cette méthode est beaucoup plus puissante qu'il n'y paraît à première vue. Elle peut trier non seulement des nombres, mais également n'importe quel objet, en fonction de n'importe quel critère. Deux interfaces aident la méthode à le faire : Comparable et Comparator . "

"Parfois, vous devez trier des objets, pas des nombres. Par exemple, supposons que vous ayez une liste de personnes et que vous souhaitiez les trier par âge. Nous avons l'interface Comparable pour cela."

"Laissez-moi d'abord vous montrer un exemple, puis tout deviendra plus clair :"

Exemple
public class Woman implements Comparable<Woman>
{
public int age;

public Woman(int age) {
this.age = age;
}

public int compareTo(Woman o)
{
return this.age - o.age;
}
}
Un exemple de la façon dont il pourrait être utilisé :
public static void main(String[] args )
{
ArrayList<Woman> women = new ArrayList<Woman>();
women.add(new Woman(18));
women.add(new Woman(21));
women.add(new Woman(5));

Collections.sort(women);
}

"Pour trier des objets, il faut d'abord savoir les comparer. Pour cela, on utilise Comparable. L' interface Comparable est générique, ce qui signifie qu'elle accepte un argument de type. Elle n'a qu'une seule méthode générique : compareTo(T o). Cette méthode compare l'objet courant (this) et un objet passé en argument (o), c'est-à-dire qu'il faut implémenter cette méthode dans notre classe puis l'utiliser pour comparer l'objet courant (this) avec l'objet passé. "

"Et comment compareTo fonctionne-t-il ? Je m'attendais à ce qu'il renvoie vrai ou faux selon que l'objet passé était plus grand ou plus petit."

"Les choses sont plus délicates ici. La méthode compareTo ne renvoie pas vrai/faux. Au lieu de cela, elle renvoie un int. Ceci est en fait fait pour plus de simplicité.

"Lorsqu'un ordinateur a besoin de déterminer si un nombre est supérieur à un autre, il soustrait simplement le deuxième nombre du premier, puis examine le résultat. Si le résultat est 0, alors les nombres sont égaux. Si le résultat est inférieur à zéro , alors le deuxième nombre est plus grand. Et si le résultat est plus grand que zéro, alors le premier nombre est plus grand."

"La même logique s'applique ici. Selon la spécification, la méthode compareTo doit renvoyer zéro si les objets comparés sont égaux. Si la méthode compareTo renvoie un nombre supérieur à zéro, alors notre objet est supérieur à l'objet passé. "Si la méthode compareTo renvoie un nombre inférieur à zéro, alors 'this' est inférieur à l'objet passé."

"C'est un peu bizarre."

"Oui, mais si vous comparez des objets simplement en fonction d'une propriété numérique, vous pouvez simplement renvoyer la différence entre eux en soustrayant l'un de l'autre. Exactement comme cela a été fait dans l'exemple ci-dessus."

public int compareTo(Woman o)
{
return this.age - o.age;
}

"Je pense que je comprends tout. Mais peut-être pas. Mais presque tout."

"Génial. Considérons maintenant un problème plus pratique. Supposons que vous ayez écrit un site Web sympa pour fabriquer des vêtements pour femmes en Chine. Vous utilisez une classe Femme pour décrire vos clients. Vous avez même créé une page Web avec un tableau où vous pouvez tous les voir . Mais il y a un problème…"

"Votre objet Femme contient non seulement un âge, mais aussi tout un tas d'autres données : prénom, nom, taille, poids, nombre d'enfants, etc."

"Le tableau des utilisateurs comporte de nombreuses colonnes, et voici la question : comment triez-vous vos utilisateurs selon les différents critères ? Par poids, par âge, par nom de famille ?"

"Hmm. Ouais, je vois souvent des tableaux qui vous permettent de trier par colonne. Alors, comment faites-vous ça ?"

« Pour cela, nous avons la deuxième interface dont je voulais vous parler aujourd'hui : l'interface Comparator. Elle a aussi une méthode de comparaison, mais elle prend deux arguments, pas un : int compare(T o1, T o2). travaux:"

Exemple
public class Woman
{
public int age;
public int childrenCount;
public int weight;
public int height;
public String name;

public Woman(int age) {
this.age = age;
}
}
Un exemple de la façon dont il pourrait être utilisé :
public static void main(String[] args )
{
ArrayList<Woman> women = new ArrayList<Woman>();
women.add(new Woman(18));
women.add(new Woman(21));
women.add(new Woman(5));

Comparator<Woman> compareByHeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.height - o2.height;
}
};

Collections.sort(women, compareByHeight);
}

"L'interface Comparator ne cache pas la logique de comparaison d'objets à l'intérieur de la classe des objets comparés. Au lieu de cela, elle est implémentée dans une classe distincte."

"Ainsi, je pourrais créer plusieurs classes qui implémentent l'interface Comparator, et faire en sorte que chacune d'entre elles compare différentes propriétés ? Poids dans l'une, âge dans l'autre et taille dans la troisième ?"

"Oui, c'est très simple et pratique."

"Nous appelons simplement la méthode Collections.sort , en passant une liste d'objets et un autre objet spécial comme deuxième argument, qui implémente l' interface Comparator et vous indique comment comparer correctement des paires d'objets dans le processus de tri."

"Hmm. Je pense que j'ai tout compris. Laissez-moi essayer. Disons que je dois trier les utilisateurs en fonction de leur poids. Ce serait quelque chose comme ça :"

Exemple de tri des utilisateurs par poids :
Comparator<Woman> compareByWeight = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.weight - o2.weight;
}
};

Collections.sort(women, compareByWeight);

"Oui, exactement."

"Super. Mais que se passe-t-il si je veux trier dans l'ordre inverse ?"

"Pensez-y. La réponse est très simple!"

"Je l'ai! Comme ça:"

Tri par ordre croissant :
return o1.weight - o2.weight;
Tri par ordre décroissant :
return o2.weight – o1.weight;

"Bien. Bravo."

« Et si je veux trier par nom de famille ? Comment trier les chaînes, Bilaabo ?

"La classe String implémente déjà la méthode compareTo. Il vous suffit de l'appeler :"

Exemple de tri des utilisateurs par nom :
Comparator<Woman> compareByName = new Comparator<Woman>() {
public int compare(Woman o1, Woman o2) {
return o1.name.compareTo(o2.name);
}
};

Collections.sort(women, compareByName);

"C'était une excellente leçon, Bilaabo. Merci beaucoup."

« Et merci à toi, mon ami !