Ітератори списку гарантують насамперед, що ви отримаєте елементи списку у внутрішньому порядку списку (він же. Порядок вставки ). Більш конкретно, це в порядку, коли ви вставили елементи, або в тому, як ви маніпулювали списком. Сортування можна розглядати як маніпулювання структурою даних, і існує кілька способів сортування списку.
Я замовляю способи в порядку корисності, як я особисто бачу це:
1. Розгляньте натомість використання Set
або Bag
колекції
ПРИМІТКА. Цей варіант я ставлю вгорі, тому що це, як правило, ви хочете зробити в будь-якому випадку.
Відсортований набір автоматично сортує колекцію при вставці , тобто означає, що вона виконує сортування під час додавання елементів у колекцію. Це також означає, що вам не потрібно вручну сортувати їх.
Крім того, якщо ви впевнені, що вам не потрібно турбуватися про (або мати) дублікати елементів, то ви можете використовувати TreeSet<T>
замість цього. Він реалізує SortedSet
та NavigableSet
інтерфейси та працює так, як ви, напевно, очікували зі списку:
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"
Якщо ви не хочете природного впорядкування, ви можете скористатися параметром конструктора, який приймає a Comparator<T>
.
Крім того, ви можете використовувати мультисети (також відомі як Bags ) , тобто, Set
що дозволяє повторювати елементи, а натомість є сторонні реалізації. Найбільш помітно з бібліотек Guava є такий TreeMultiset
, який працює дуже схоже на TreeSet
.
2. Сортуйте свій список Collections.sort()
Як було сказано вище, сортування List
s - це маніпулювання структурою даних. Тож для ситуацій, коли вам потрібно "одне джерело істини", яке буде сортоване різними способами, а потім їх сортування вручну - це шлях.
Ви можете сортувати свій список java.util.Collections.sort()
методом. Ось зразок коду про те, як:
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"
Використання компараторів
Очевидною перевагою є те, що ви можете використовувати Comparator
в sort
методі. Java також надає деякі реалізації для Comparator
таких, Collator
які корисні для чутливих до локалізації рядків. Ось один із прикладів:
Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing
Collections.sort(strings, usCollator);
Сортування в одночасних середовищах
Зауважте, що використання sort
методу не є дружнім у паралельних середовищах, оскільки екземпляр колекції буде маніпулювати, і вам слід замість цього використати незмінні колекції. Це те, що Guava забезпечує у Ordering
класі та є простим однолінійним:
List<string> sorted = Ordering.natural().sortedCopy(strings);
3. Обгорніть свій список java.util.PriorityQueue
Хоча в Java немає відсортованого списку, однак є відсортована черга, яка, ймовірно, спрацювала б так само добре для вас. Це java.util.PriorityQueue
клас.
Ніко Хааз зв'язав у коментарях відповідне питання, яке також відповідає на це.
У відсортованій колекції ви, швидше за все, не хочете маніпулювати внутрішньою структурою даних, через що PriorityQueue не реалізує інтерфейс списку (тому що це надасть вам прямий доступ до його елементів).
Накладіть на PriorityQueue
ітератор
У PriorityQueue
класі реалізує Iterable<E>
і Collection<E>
інтерфейси , тому він може бути ітерованих як зазвичай. Однак ітератор не гарантує повернення елементів у відсортованому порядку. Натомість (як в коментарях вказує Альдерат), вам потрібно буде poll()
в черзі, поки вона не порожня.
Зауважте, що ви можете перетворити список у чергу пріоритету через конструктор, який приймає будь-яку колекцію :
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. Напишіть власний SortedList
клас
ПРИМІТКА. Вам цього не слід було робити.
Ви можете написати власний клас List, який сортує кожного разу, коли ви додаєте новий елемент. Це може бути досить важким для обчислень залежно від вашої реалізації та безглуздо , якщо ви не хочете робити це як вправу через дві основні причини:
- Він порушує контракт, який
List<E>
має інтерфейс, оскільки add
методи повинні гарантувати, що елемент буде перебувати в індексі, який вказує користувач.
- Навіщо винаходити колесо? Ви повинні використовувати TreeSet або Multisets замість цього, як зазначено в першій точці вище.
Однак якщо ви хочете зробити це як вправу, тут є зразок коду для початку роботи, він використовує AbstractList
абстрактний клас:
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();
}
}
Зауважте, що якщо ви не перекрили потрібні вам методи, то за замовчуванням реалізація AbstractList
буде кидати UnsupportedOperationException
s.