web-dev-qa-db-fra.com

Tri d'une collection d'objets

Si j'ai une simple liste de chaînes:

List<String> stringList = new ArrayList<String>();

Je peux le trier avec:

Collections.sort(stringList);

Mais supposons que j'ai une classe Person:

public class Person
{
   private String name;
   private Integer age;
   private String country;
}

Et une liste de celle-ci:

List<Person> personList = new ArrayList<Person>();

Et je veux le trier parfois par nom, parfois par âge, parfois par pays.

Quel est le moyen le plus simple d'y parvenir?

Je sais que je peux implémenter l'interface Comparable, mais cela semble me limiter à le trier par une propriété spécifique.

57
Knut Arne Vedaa

Implémentez l'interface Comparator (une fois pour chaque ordre de tri) et utilisez la méthode Collections.sort () qui prend un comparateur comme paramètre supplémentaire.

34
Michael Borgwardt

Collections.sort peut être appelé avec un comparateur personnalisé. Et ce comparateur peut être implémenté pour permettre le tri dans différents ordres de tri. Voici un exemple (pour votre modèle de personne - avec l'âge en tant que nombre entier):

public class FlexiblePersonComparator implements Comparator<Person> {
  public enum Order {Name, Age, Country}

  private Order sortingBy = Name;

  @Override
  public int compare(Person person1, Person person2) {
    switch(sortingBy) {
      case Name: return person1.name.compareTo(person2.name);
      case Age: return person1.age.compareTo(person2.age);
      case Country: return person1.country.compareTo(person2.country);
    }
    throw new RuntimeException("Practically unreachable code, can't be thrown");
  }

  public void setSortingBy(Order sortBy) {
    this.sortingBy = sortingBy;
  }
}

Et vous l'utilisez comme ça (en supposant que les personnes est un champ):

public void sortPersonsBy(FlexiblePersonComparator.Order sortingBy) {
  List<Person> persons = this.persons;  // useless line, just for clarification
  FlexiblePersonComparator comparator = new FlexiblePersonComparator();
  comparator.setSortingBy(sortingBy);
  Collections.sort(persons, comparator); // now we have a sorted list
}
48
Andreas_D

Merci aux intervenants. Pour le bénéfice des autres, je voudrais inclure un exemple complet.

La solution consiste à créer les classes supplémentaires suivantes:

public class NameComparator implements Comparator<Person>
{
    public int compare(Person o1, Person o2)
    {
       return o1.getName().compareTo(o2.getName());
   }
}

public class AgeComparator implements Comparator<Person>
{
    public int compare(Person o1, Person o2)
    {
        return o1.getAge().compareTo(o2.getAge());
    }
}

public class CountryComparator implements Comparator<Person>
{
    public int compare(Person o1, Person o2)
    {
        return o1.getCountry().compareTo(o2.getCountry());
    }
}

La liste peut alors être triée comme ceci:

Collections.sort(personList, new NameComparator());
Collections.sort(personList, new AgeComparator());
Collections.sort(personList, new CountryComparator());
17
Knut Arne Vedaa

Pour ce faire, Java 8 utilise List.sort comme suit:

personList.sort(Comparator.comparing(Person::getName));

Pour citer Stuart Marks } _ dans sa réponse à ici .

C'est le gros avantage de la méthode d'extension List.sort(cmp) par rapport à Collections.sort(list, cmp). Cela peut sembler être simplement un petit avantage syntaxique de pouvoir écrire myList.sort(cmp) au lieu de Collections.sort(myList, cmp). La différence est que myList.sort(cmp), étant une méthode d'extension d'interface, peut être remplacé par l'implémentation List spécifique. Par exemple, ArrayList.sort(cmp) trie la liste sur place à l'aide de Arrays.sort() alors que l'implémentation par défaut implémente l'ancienne technique copyout-sort-copyback.

10
aioobe

Vous pouvez aussi utiliser le BeanComparator from Apache commons beanutils, comme ceci:

Collections.sort(personList, new BeanComparator("name"));
6
Jörn Horstmann

Implémentez 3 types différents de comparateur.

vous pouvez ajouter le comparateur à la commande de tri. Le comparateur que vous définissez triera les éléments par nom, âge ou quoi que ce soit.

Collections.sort(list, new Comparator() {

        public int compare(Object arg0, Object arg1) {
            if (!(arg0 instanceof Person)) {
                return -1;
            }
            if (!(arg1 instanceof Person)) {
                return -1;
            }

            Person pers0 = (Person)arg0;
            Person pers1 = (Person)arg1;


            // COMPARE NOW WHAT YOU WANT
            // Thanks to Steve Kuo for your comment!
            return pers0.getAge() - pers1.getAge();
        }
    });
3
Markus Lausberg

La méthode Collections.sort peut être invoquée avec un deuxième argument qui est le comparateur à utiliser . Créez 3 comparateurs et utilisez celui de votre choix, le cas échéant.

Collections.sort(list , new Comparator() {
        public int compare(Object o1, Object o2) {
          ...
        }
      });
2
z5h

En utilisant lambdaj ( http://code.google.com/p/lambdaj/ ), vous pouvez obtenir ce que vous demandez de la manière suivante:

sort (personList, on (Person.class) .getName ());

sort (personList, on (Person.class) .getAge ());

sort (personList, on (Person.class) .getCountry ());

0
Mario Fusco

J'ai posé une question très similaire (sur la recherche plutôt que sur le tri), peut-être y at-il des informations utiles (j'ai fini par utiliser un enum qui implémente Comparator donc je passe la valeur enum comme sélecteur de comparaison).

0
Jason S