Итераторы списка гарантируют, прежде всего, то, что вы получите элементы списка во внутреннем порядке списка (он же порядок вставки ). Точнее, в том порядке, в котором вы вставили элементы, или о том, как вы манипулировали списком. Сортировка может рассматриваться как манипулирование структурой данных, и существует несколько способов сортировки списка.
Я закажу пути в порядке полезности, как лично вижу:
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()
Как упоминалось выше, сортировка 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 не реализует интерфейс 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
сгенерируют UnsupportedOperationException
s.