Итераторы списка гарантируют, прежде всего, то, что вы получите элементы списка во внутреннем порядке списка (он же порядок вставки ). Точнее, в том порядке, в котором вы вставили элементы, или о том, как вы манипулировали списком. Сортировка может рассматриваться как манипулирование структурой данных, и существует несколько способов сортировки списка.
Я закажу пути в порядке полезности, как лично вижу:
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"
Если вы не хотите естественного упорядочения, вы можете использовать параметр конструктора, который принимает Comparator<T>.
В качестве альтернативы, вы можете использовать Multisets (также известный как Bags ) , то есть, Setкоторый позволяет дублировать элементы, и есть их сторонние реализации. В частности, из библиотек Guava есть TreeMultiset, который работает так же, как TreeSet.
2. Сортируйте свой список с помощью Collections.sort()
Как упоминалось выше, сортировка Lists - это манипулирование структурой данных. Так что для ситуаций, когда вам нужен «один источник правды», который будет отсортирован различными способами, тогда сортировка вручную - это путь.
Вы можете отсортировать свой список с помощью 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 не реализует интерфейс List (потому что это даст вам прямой доступ к его элементам).
Будьте осторожны с 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сгенерируют UnsupportedOperationExceptions.