Listeniteratoren garantieren in erster Linie, dass Sie die Elemente der Liste in der internen Reihenfolge der Liste (auch bekannt als Einfügereihenfolge ) erhalten. Genauer gesagt in der Reihenfolge, in der Sie die Elemente eingefügt haben oder wie Sie die Liste bearbeitet haben. Das Sortieren kann als Manipulation der Datenstruktur angesehen werden, und es gibt verschiedene Möglichkeiten, die Liste zu sortieren.
Ich werde die Wege in der Reihenfolge ihrer Nützlichkeit ordnen, wie ich es persönlich sehe:
1. Erwägen Sie stattdessen die Verwendung von Set
oder Bag
Sammlungen
HINWEIS: Ich habe diese Option oben platziert, da Sie dies normalerweise sowieso tun möchten.
Ein sortierter Satz sortiert die Sammlung beim Einfügen automatisch. Dies bedeutet, dass die Sortierung durchgeführt wird, während Sie der Sammlung Elemente hinzufügen. Dies bedeutet auch, dass Sie es nicht manuell sortieren müssen.
Wenn Sie sicher sind, dass Sie sich keine Gedanken über doppelte Elemente machen müssen (oder haben), können Sie TreeSet<T>
stattdessen das verwenden. Es implementiert SortedSet
und NavigableSet
verbindet und funktioniert so, wie Sie es wahrscheinlich von einer Liste erwarten würden:
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"
Wenn Sie die natürliche Reihenfolge nicht möchten, können Sie den Konstruktorparameter verwenden, der a akzeptiert Comparator<T>
.
Alternativ Sie können Multimengen (auch bekannt als Beutel ) , das ist eine , Set
die doppelten Elemente erlaubt es , statt und es gibt Drittanbieter - Implementierungen von ihnen. Vor allem aus den Guava-Bibliotheken gibt es eine TreeMultiset
, die sehr ähnlich funktioniert wie die TreeSet
.
2. Sortieren Sie Ihre Liste mit Collections.sort()
Wie oben erwähnt, ist das Sortieren von List
s eine Manipulation der Datenstruktur. In Situationen, in denen Sie "eine Quelle der Wahrheit" benötigen, die auf verschiedene Arten sortiert wird, ist das manuelle Sortieren der richtige Weg.
Sie können Ihre Liste mit der java.util.Collections.sort()
Methode sortieren . Hier ist ein Codebeispiel, wie:
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"
Komparatoren verwenden
Ein klarer Vorteil ist, dass Sie Comparator
in der sort
Methode verwenden können. Java bietet auch einige Implementierungen für Comparator
solche, wie z. B. die, Collator
die für länderspezifische Sortierzeichenfolgen nützlich sind. Hier ist ein Beispiel:
Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing
Collections.sort(strings, usCollator);
Sortieren in gleichzeitigen Umgebungen
Beachten Sie jedoch, dass die Verwendung der sort
Methode in gleichzeitigen Umgebungen nicht benutzerfreundlich ist, da die Sammlungsinstanz manipuliert wird und Sie stattdessen die Verwendung unveränderlicher Sammlungen in Betracht ziehen sollten. Dies ist etwas, was Guava in der Ordering
Klasse bietet und ist ein einfacher Einzeiler:
List<string> sorted = Ordering.natural().sortedCopy(strings);
3. Wickeln Sie Ihre Liste mit ein java.util.PriorityQueue
Obwohl es in Java keine sortierte Liste gibt, gibt es eine sortierte Warteschlange, die wahrscheinlich genauso gut für Sie funktionieren würde. Es ist die java.util.PriorityQueue
Klasse.
Nico Haase hat in den Kommentaren eine verwandte Frage verlinkt , die auch diese beantwortet.
In einer sortierten Sammlung möchten Sie höchstwahrscheinlich die interne Datenstruktur nicht manipulieren, weshalb PriorityQueue die List-Schnittstelle nicht implementiert (da Sie dadurch direkten Zugriff auf ihre Elemente erhalten).
Vorsichtsmaßnahme für den PriorityQueue
Iterator
Die PriorityQueue
Klasse implementiert die Schnittstellen Iterable<E>
und Collection<E>
, sodass sie wie gewohnt iteriert werden kann. Es ist jedoch nicht garantiert, dass der Iterator Elemente in der sortierten Reihenfolge zurückgibt. Stattdessen müssen Sie (wie Alderath in den Kommentaren hervorhebt) in poll()
die Warteschlange gestellt werden, bis sie leer ist.
Beachten Sie, dass Sie eine Liste über den Konstruktor, der eine beliebige Sammlung akzeptiert, in eine Prioritätswarteschlange konvertieren können :
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. Schreiben Sie Ihre eigene SortedList
Klasse
HINWEIS: Sie sollten dies nicht tun müssen.
Sie können Ihre eigene List-Klasse schreiben, die jedes Mal sortiert wird, wenn Sie ein neues Element hinzufügen. Dies kann abhängig von Ihrer Implementierung ziemlich rechenintensiv werden und ist aus zwei Hauptgründen sinnlos , es sei denn, Sie möchten es als Übung ausführen:
- Es bricht den Vertrag, den die
List<E>
Schnittstelle hat, weil die add
Methoden sicherstellen sollten, dass sich das Element in dem vom Benutzer angegebenen Index befindet.
- Warum das Rad neu erfinden? Sie sollten stattdessen das TreeSet oder Multisets verwenden, wie im ersten Punkt oben ausgeführt.
Wenn Sie dies jedoch als Übung ausführen möchten, verwenden Sie hier ein Codebeispiel, um den Einstieg zu erleichtern. Es wird die AbstractList
abstrakte Klasse verwendet:
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();
}
}
Beachten Sie , wenn Sie die Methoden nicht außer Kraft gesetzt haben , Sie benötigen, dann von dem Standardimplementierungen AbstractList
werfen UnsupportedOperationException
s.