J'essaie d'apprendre le comparateur à Java et j'ai trouvé ce bel exemple en ligne. Ma question est de savoir comment ce code pourrait-il être modifié pour que les noms des animaux domestiques soient classés par âge et par ordre décroissant afin que le plus ancien soit le dernier et le plus récent est le dernier?
class Dog implements Comparator<Dog>, Comparable<Dog>{
private String name;
private int age;
Dog(){
}
Dog(String n, int a){
name = n;
age = a;
}
public String getDogName(){
return name;
}
public int getDogAge(){
return age;
}
// Overriding the compareTo method
public int compareTo(Dog d){
return (this.name).compareTo(d.name);
}
// Overriding the compare method to sort the age
public int compare(Dog d, Dog d1){
return d.age - d1.age;
}
}
public class Example{
public static void main(String args[]){
// Takes a list o Dog objects
List<Dog> list = new ArrayList<Dog>();
list.add(new Dog("Shaggy",3));
list.add(new Dog("Lacy",2));
list.add(new Dog("Roger",10));
list.add(new Dog("Tommy",4));
list.add(new Dog("Tammy",1));
Collections.sort(list);// Sorts the array list
for(Dog a: list)//printing the sorted list of names
System.out.print(a.getDogName() + ", ");
// Sorts the array list using comparator
Collections.sort(list, new Dog());
System.out.println(" ");
for(Dog a: list)//printing the sorted list of ages
System.out.print(a.getDogName() +" : "+
a.getDogAge() + ", ");
}
}
Simplement changer
public int compare(Dog d, Dog d1) {
return d.age - d1.age;
}
à
public int compare(Dog d, Dog d1) {
return d1.age - d.age;
}
devrait les trier dans l’ordre inverse de l’âge si c’est ce que vous recherchez.
Mettre à jour:
@Arian a raison dans ses commentaires. L'un des moyens acceptés de déclarer un comparateur pour un chien serait de le déclarer comme un champ final statique public dans la classe elle-même.
class Dog implements Comparable<Dog> {
private String name;
private int age;
public static final Comparator<Dog> DESCENDING_COMPARATOR = new Comparator<Dog>() {
// Overriding the compare method to sort the age
public int compare(Dog d, Dog d1) {
return d.age - d1.age;
}
};
Dog(String n, int a) {
name = n;
age = a;
}
public String getDogName() {
return name;
}
public int getDogAge() {
return age;
}
// Overriding the compareTo method
public int compareTo(Dog d) {
return (this.name).compareTo(d.name);
}
}
Vous pouvez ensuite l'utiliser n'importe où dans votre code pour comparer les chiens de la manière suivante:
// Sorts the array list using comparator
Collections.sort(list, Dog.DESCENDING_COMPARATOR);
Une autre chose importante à retenir lors de l’implémentation de Comparable est qu’il est important que compareTo fonctionne de manière cohérente avec égal. Bien que cela ne soit pas obligatoire, le fait de ne pas le faire pourrait entraîner un comportement étrange sur certaines collections, telles que certaines implémentations de Sets. Voir this post pour plus d’informations sur les principes valables de mise en œuvre de compareTo.
Mise à jour 2: Chris a raison, ce code est susceptible de déborder pour de grandes valeurs négatives d’âge. La méthode correcte pour implémenter cela dans Java 7 et les versions ultérieures serait Integer.compare(d.age, d1.age)
au lieu de d.age - d1.age
.
Mise à jour 3: Avec Java 8, votre comparateur pourrait être écrit beaucoup plus succinctement de la manière suivante:
public static final Comparator<Dog> DESCENDING_COMPARATOR =
Comparator.comparing(Dog::getDogAge).reversed();
La syntaxe pour Collections.sort
reste la même, mais compare
peut être écrit en tant que
public int compare(Dog d, Dog d1) {
return DESCENDING_COMPARATOR.compare(d, d1);
}
Il suffit de remplacer:
return d.age - d1.age;
Par:
return ((Integer)d.age).compareTo(d1.age);
Ou inversez pour inverser la liste:
return ((Integer)d1.age).compareTo(d.age);
MODIFIER:
Correction du "problème de mémoire".
En effet, la meilleure solution consiste à changer le champ age
de la classe Dog
en Integer
, car il présente de nombreux avantages, comme la possibilité null
.
public class DogAgeComparator implements Comparator<Dog> {
public int compare(Dog o1, Dog o2) {
return Integer.compare(o1.getAge(), o2.getId());
}
}
À partir de Java 8, vous pouvez utiliser:
Comparator.comparingInt(Dog::getDogAge).reversed();
Un moyen simple est
Comparator<Dog> ageAscendingComp = ...;
Comparator<Dog> ageDescendingComp = Collections.reverseOrder(ageAscendingComp);
// then call the sort method
Sur une note de côté, Dog ne devrait vraiment pas implémenter Comparator
. Cela signifie que vous devez faire des choses étranges comme
Collections.sort(myList, new Dog("Rex", 4));
// ^-- why is a new dog being made? What are we even sorting by?!
Collections.sort(myList, myList.get(0));
// ^-- or perhaps more confusingly
Vous devriez plutôt faire Compartors en tant que classes séparées.
par exemple.
public class DogAgeComparator implments Comparator<Dog> {
public int compareTo(Dog d1, Dog d2) {
return d1.getAge() - d2.getAge();
}
}
Cela présente l'avantage supplémentaire que vous pouvez utiliser le nom de la classe pour indiquer comment le comparateur va trier la liste. par exemple.
Collections.sort(someDogs, new DogNameComparator());
// now in name ascending order
Collections.sort(someDogs, Collections.reverseOrder(new DogAgeComparator()));
// now in age descending order
De plus, vous ne devriez pas avoir Dog implémenter Comparable
. L’interface Comparable
indique qu’il existe un moyen naturel et naturel de classer ces objets (comme des nombres et des chaînes). Or, ce n'est pas le cas pour les objets Dog, car vous souhaiterez parfois trier par âge et parfois par nom.