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.
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.
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
}
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());
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 écriremyList.sort(cmp)
au lieu deCollections.sort(myList, cmp)
. La différence est quemyList.sort(cmp)
, étant une méthode d'extension d'interface, peut être remplacé par l'implémentationList
spécifique. Par exemple,ArrayList.sort(cmp)
trie la liste sur place à l'aide deArrays.sort()
alors que l'implémentation par défaut implémente l'ancienne technique copyout-sort-copyback.
Vous pouvez aussi utiliser le BeanComparator from Apache commons beanutils, comme ceci:
Collections.sort(personList, new BeanComparator("name"));
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();
}
});
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) {
...
}
});
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 ());
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).