Gli iteratori di elenco garantiscono innanzitutto di ottenere gli elementi dell'elenco nell'ordine interno dell'elenco (ovvero l'ordine di inserimento ). Più specificamente è nell'ordine in cui hai inserito gli elementi o su come hai manipolato l'elenco. L'ordinamento può essere visto come una manipolazione della struttura dei dati e ci sono diversi modi per ordinare l'elenco.
Ordinerò i modi in ordine di utilità come la vedo personalmente:
1. Prendi invece in considerazione l'utilizzo Set
o le Bag
raccolte
NOTA: ho messo questa opzione in alto perché questo è ciò che normalmente si desidera fare comunque.
Un set ordinato ordina automaticamente la raccolta al momento dell'inserimento , il che significa che esegue l'ordinamento mentre si aggiungono elementi alla raccolta. Significa anche che non è necessario ordinarlo manualmente.
Inoltre, se sei sicuro di non doverti preoccupare (o avere) degli elementi duplicati, puoi usare TreeSet<T>
invece. Implementa SortedSet
e si NavigableSet
interfaccia e funziona come probabilmente ti aspetteresti da un elenco:
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"
Se non si desidera l'ordine naturale, è possibile utilizzare il parametro del costruttore che accetta a Comparator<T>
.
In alternativa, è possibile utilizzare Multiset (noto anche come Borse ) , ovvero un Set
elemento che consente elementi duplicati, mentre sono presenti implementazioni di terze parti. In particolare dalle librerie di Guava c'è un TreeMultiset
, che funziona in modo molto simile al TreeSet
.
2. Ordina l'elenco con Collections.sort()
Come accennato in precedenza, l'ordinamento di List
s è una manipolazione della struttura dei dati. Quindi, per le situazioni in cui hai bisogno di "una sola fonte di verità" che verrà ordinata in vari modi, l'ordinamento manuale è la strada da percorrere.
Puoi ordinare la tua lista con il java.util.Collections.sort()
metodo. Ecco un esempio di codice su come:
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"
Utilizzando i comparatori
Un chiaro vantaggio è che è possibile utilizzare Comparator
nel sort
metodo. Java fornisce anche alcune implementazioni Comparator
come quella Collator
utile per le stringhe di ordinamento sensibili alle impostazioni locali. Ecco un esempio:
Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing
Collections.sort(strings, usCollator);
Ordinamento in ambienti simultanei
Si noti tuttavia che l'utilizzo del sort
metodo non è intuitivo in ambienti concorrenti, poiché l'istanza della raccolta verrà manipolata e si dovrebbe invece considerare l'utilizzo di raccolte immutabili. Questo è qualcosa che Guava fornisce nella Ordering
classe ed è un semplice one-liner:
List<string> sorted = Ordering.natural().sortedCopy(strings);
3. Avvolgere l'elenco con java.util.PriorityQueue
Sebbene non ci sia un elenco ordinato in Java, esiste comunque una coda ordinata che probabilmente funzionerebbe altrettanto bene per te. È la java.util.PriorityQueue
classe.
Nico Haase ha collegato nei commenti una domanda correlata che risponde anche a questo.
In una raccolta ordinata molto probabilmente non vorrai manipolare la struttura interna dei dati, motivo per cui PriorityQueue non implementa l'interfaccia Elenco (perché ciò ti darebbe accesso diretto ai suoi elementi).
Avvertenza PriorityQueue
sull'iteratore
La PriorityQueue
classe implementa le interfacce Iterable<E>
e in Collection<E>
modo che possa essere ripetuta come al solito. Tuttavia, non è garantito che l'iteratore restituisca elementi nell'ordine ordinato. Invece (come sottolinea Alderath nei commenti) è necessario che poll()
la coda sia vuota.
Nota che puoi convertire un elenco in una coda prioritaria tramite il costruttore che accetta qualsiasi raccolta :
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. Scrivi la tua SortedList
lezione
NOTA: non dovresti farlo.
È possibile scrivere la propria classe Elenco che ordina ogni volta che si aggiunge un nuovo elemento. Questo può diventare piuttosto pesante a seconda della tua implementazione ed è inutile , a meno che tu non voglia farlo come esercizio, per due motivi principali:
- Rompe il contratto che l'
List<E>
interfaccia ha perché i add
metodi dovrebbero garantire che l'elemento risieda nell'indice specificato dall'utente.
- Perché reinventare la ruota? Dovresti usare TreeSet o Multiset invece come indicato nel primo punto sopra.
Tuttavia, se vuoi farlo come esercizio qui è un esempio di codice per iniziare, usa la AbstractList
classe astratta:
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();
}
}
Nota che se non hai ignorato i metodi di cui hai bisogno, le implementazioni predefinite AbstractList
genereranno UnsupportedOperationException
s.