Есть ли набор для сохранения порядка вставки, который также реализует List?
Я пытаюсь найти реализацию java.util.List
и java.util.Set
одновременно в Java. Я хочу, чтобы этот класс допускал только уникальные элементы (как Set
) и сохранял их порядок (например, List
). Он существует в JDK 6?
Важно иметь List<T>#add(int, T)
, поэтому я могу вставить его в определенную позицию.
Ответы
Ответ 1
TreeSet
отсортирован по порядку элементов; LinkedHashSet
сохраняет порядок вставки. Надеюсь, один из них - это то, что вы искали.
Вы указали, что хотите иметь возможность вставлять в произвольном месте, я подозреваю, что вам придется написать свой собственный - просто создайте класс, содержащий HashSet<T>
и ArrayList<T>
; при добавлении элемента, проверьте, есть ли он в наборе, прежде чем добавить его в список.
В качестве альтернативы Apache commons-collection4 предлагает ListOrderedSet
и SetUniqueList
, которые ведут себя аналогично и должны отвечать заданным требованиям.
Ответ 2
LinkedHashSet - это ответ.
Итерационное упорядочение и уникальность.
http://download.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html
Ответ 3
Вы имеете в виду как LinkedHashSet
? Это сохраняет порядок ввода, но не позволяет дублировать.
IMHO, это необычное требование, но вы можете написать список без дубликатов.
class SetList<T> extends ArrayList<T> {
@Override
public boolean add(T t) {
return !super.contains(t) && super.add(t);
}
@Override
public void add(int index, T element) {
if (!super.contains(element)) super.add(index, element);
}
@Override
public boolean addAll(Collection<? extends T> c) {
boolean added = false;
for (T t : c)
added |= add(t);
return added;
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
boolean added = false;
for (T t : c)
if (!super.contains(t)) {
super.add(index++, t);
added = true;
}
return added;
}
}
Ответ 4
Вы не можете реализовать List
и Set
сразу без нарушения контракта. См., Например, контракт Set.hashCode
:
Хэш-код набора определяется как сумма хэш-кодов элементов в наборе, где хэш-код нулевого элемента определяется как нуль.
С другой стороны, здесь заключен договор List.hashCode
:
Хэш-код списка определяется как результат следующего вычисления:
int hashCode = 1;
for (E e : list)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
Таким образом, невозможно реализовать единый класс, который гарантирует выполнение обоих контрактов. Эта же проблема для реализации equals
.
Ответ 5
Если вы не будете ограничивать себя JDK 6, вы можете использовать коллекцию общих коллекций Apache, которая предлагает точное соответствие для вашей потребности - ListOrderedSet. Это как List
и Set
вместе взятые:)
Ответ 6
У меня была аналогичная проблема, поэтому я написал свой собственный. См. здесь. IndexedArraySet
расширяет ArrayList
и реализует Set
, поэтому он должен поддерживать все операции, которые вам нужны. Обратите внимание: вставка элементов в середину ArrayList
может быть медленной для больших списков, потому что все перечисленные элементы необходимо переместить. Мой IndexedArraySet
не меняет этого.
Ответ 7
Другой вариант (минус требование интерфейса List
) - это Guava ImmutableSet
, который сохраняет порядок вставки. Из их wiki-страница:
За исключением отсортированных коллекций, порядок сохраняется из времени построения. Например,
ImmutableSet.of("a", "b", "c", "a", "d", "b")
будет перебирать свои элементы в порядке "a", "b", "c", "d".