Les itérateurs de liste garantissent avant tout que vous obtenez les éléments de la liste dans l'ordre interne de la liste (aka. Ordre d'insertion ). Plus précisément, c'est dans l'ordre dans lequel vous avez inséré les éléments ou dans la façon dont vous avez manipulé la liste. Le tri peut être considéré comme une manipulation de la structure des données, et il existe plusieurs façons de trier la liste.
Je vais ordonner les chemins dans l'ordre d' utilité tel que je le vois personnellement:
1. Pensez à utiliser Set
ou Bag
collections à la place
REMARQUE: je mets cette option en haut parce que c'est ce que vous voulez normalement faire de toute façon.
Un ensemble trié trie automatiquement la collection à l'insertion , ce qui signifie qu'il effectue le tri pendant que vous ajoutez des éléments dans la collection. Cela signifie également que vous n'avez pas besoin de le trier manuellement.
De plus, si vous êtes sûr de ne pas avoir à vous soucier (ou d'avoir) des éléments en double, vous pouvez utiliser le à la TreeSet<T>
place. Il implémente SortedSet
et NavigableSet
interface et fonctionne comme vous l'attendriez probablement d'une liste:
TreeSet<String> set = new TreeSet<String>();
set.add("lol");
set.add("cat");
// automatically sorts natural order when adding
for (String s : set) {
System.out.println(s);
}
// Prints out "cat" and "lol"
Si vous ne voulez pas l'ordre naturel, vous pouvez utiliser le paramètre constructeur qui prend a Comparator<T>
.
Alternativement, vous pouvez utiliser des multisets (également appelés sacs ) , c'est-à-dire Set
qui autorisent les éléments en double, et il existe des implémentations tierces. Plus particulièrement à partir des bibliothèques de Guava, il y en a un TreeMultiset
, qui fonctionne beaucoup comme le TreeSet
.
2. Triez votre liste avec Collections.sort()
Comme mentionné ci-dessus, le tri de List
s est une manipulation de la structure des données. Donc, pour les situations où vous avez besoin d'une "source de vérité" qui sera triée de différentes manières, puis la trier manuellement est la voie à suivre.
Vous pouvez trier votre liste avec la java.util.Collections.sort()
méthode. Voici un exemple de code expliquant comment:
List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");
Collections.sort(strings);
for (String s : strings) {
System.out.println(s);
}
// Prints out "cat" and "lol"
Utiliser des comparateurs
Un avantage évident est que vous pouvez l'utiliser Comparator
dans la sort
méthode. Java fournit également quelques implémentations pour le Comparator
tel que le Collator
qui est utile pour les chaînes de tri sensibles aux paramètres régionaux. Voici un exemple:
Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing
Collections.sort(strings, usCollator);
Tri dans des environnements simultanés
Notez cependant que l'utilisation de la sort
méthode n'est pas conviviale dans les environnements simultanés, car l'instance de collection sera manipulée, et vous devriez plutôt envisager d'utiliser des collections immuables. C'est quelque chose que Guava fournit dans la Ordering
classe et c'est un simple doublure:
List<string> sorted = Ordering.natural().sortedCopy(strings);
3. Enveloppez votre liste avec java.util.PriorityQueue
Bien qu'il n'y ait pas de liste triée en Java, il existe cependant une file d'attente triée qui fonctionnerait probablement aussi bien pour vous. C'est la java.util.PriorityQueue
classe.
Nico Haase a lié dans les commentaires une question connexe qui répond également à cela.
Dans une collection triée, vous ne voulez probablement pas manipuler la structure de données interne, c'est pourquoi PriorityQueue n'implémente pas l'interface List (car cela vous donnerait un accès direct à ses éléments).
Avertissement sur l' PriorityQueue
itérateur
La PriorityQueue
classe implémente les interfaces Iterable<E>
et Collection<E>
afin qu'elle puisse être itérée comme d'habitude. Cependant, l'itérateur n'est pas garanti de renvoyer les éléments dans l'ordre trié. Au lieu de cela (comme le souligne Alderath dans les commentaires), vous devez mettre poll()
la file d'attente jusqu'à ce qu'elle soit vide.
Notez que vous pouvez convertir une liste en file d'attente prioritaire via le constructeur qui prend n'importe quelle collection :
List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");
PriorityQueue<String> sortedStrings = new PriorityQueue(strings);
while(!sortedStrings.isEmpty()) {
System.out.println(sortedStrings.poll());
}
// Prints out "cat" and "lol"
4. Écrivez votre propre SortedList
classe
REMARQUE: vous ne devriez pas avoir à le faire.
Vous pouvez écrire votre propre classe List qui trie chaque fois que vous ajoutez un nouvel élément. Cela peut être assez lourd à calculer en fonction de votre implémentation et est inutile , sauf si vous voulez le faire comme un exercice, pour deux raisons principales:
- Il rompt le contrat de l'
List<E>
interface car les add
méthodes doivent garantir que l'élément résidera dans l'index spécifié par l'utilisateur.
- Pourquoi réinventer la roue? Vous devez utiliser le TreeSet ou les Multisets à la place, comme indiqué au premier point ci-dessus.
Cependant, si vous voulez le faire comme un exercice, voici un exemple de code pour vous aider à démarrer, il utilise la AbstractList
classe abstraite:
public class SortedList<E> extends AbstractList<E> {
private ArrayList<E> internalList = new ArrayList<E>();
// Note that add(E e) in AbstractList is calling this one
@Override
public void add(int position, E e) {
internalList.add(e);
Collections.sort(internalList, null);
}
@Override
public E get(int i) {
return internalList.get(i);
}
@Override
public int size() {
return internalList.size();
}
}
Notez que si vous n'avez pas remplacé les méthodes dont vous avez besoin, les implémentations par défaut de AbstractList
jetteront UnsupportedOperationException
s.