web-dev-qa-db-fra.com

comparateur Java, comment trier par nombre entier?

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() + ", ");
}
}
27
Edmund Rojas

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);
}
86
Jeshurun

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.

19
elias
public class DogAgeComparator implements Comparator<Dog> {
    public int compare(Dog o1, Dog o2) {
        return Integer.compare(o1.getAge(), o2.getId());
    }
}
15
George Thekkan

À partir de Java 8, vous pouvez utiliser:

Comparator.comparingInt(Dog::getDogAge).reversed();
8
jota3

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.

4
Dunes