Существует ли набор для сохранения порядка вставки, который также реализует список? - PullRequest
82 голосов
/ 18 ноября 2011

Я пытаюсь найти реализацию java.util.List и java.util.Set одновременно в Java. Я хочу, чтобы этот класс разрешал только уникальные элементы (как Set) и сохранял их порядок (например, List). Существует ли он в JDK 6?

Важно иметь List<T>#add(int, T), чтобы я мог вставлять в определенную позицию.

Ответы [ 7 ]

200 голосов
/ 18 ноября 2011

TreeSet отсортировано по порядку элементов;LinkedHashSet сохраняет порядок вставки.Надеюсь, что один из них - то, что вам нужно.

Вы указали, что хотите иметь возможность вставлять в произвольное местоположение, я подозреваю, что вам придется написать свое собственное -просто создайте класс, содержащий HashSet<T> и ArrayList<T>;при добавлении элемента проверьте, находится ли он в наборе, прежде чем добавлять его в список.

В качестве альтернативы Apache commons-collection4 предлагает ListOrderedSet и SetUniqueList, которые ведут себя аналогично и должны отвечать заданным требованиям.

30 голосов
/ 18 ноября 2011

LinkedHashSet является ответом.

Порядок итераций и уникальность.

http://download.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html

10 голосов
/ 18 ноября 2011

Вы имеете в виду, как LinkedHashSet? Это сохраняет порядок ввода, но не допускает дублирование.

ИМХО, это необычное требование, но вы можете написать список без дубликатов.

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;
    }
}
6 голосов
/ 07 сентября 2015

Вы не можете сразу реализовать List и Set без нарушения договора. См., Например, Set.hashCode контракт:

Хеш-код набора определяется как сумма хеш-кодов элементов в наборе, где хеш-код нулевого элемента определяется как ноль.

С другой стороны, вот контракт List.hashCode:

Хеш-код списка определяется как результат следующего вычисления:

int hashCode = 1;
for (E e : list)
    hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

Так что невозможно реализовать один класс, который гарантирует выполнение обоих контрактов. Та же проблема для реализации equals.

4 голосов
/ 16 января 2014

Если вы не ограничитесь JDK 6, вы можете использовать Общие коллекции Apache библиотека, которая предлагает точное соответствие для ваших нужд - ListOrderedSet .Это как List и Set вместе взятые:)

0 голосов
/ 02 октября 2017

Другой вариант (за исключением List интерфейса) - это Guava's ImmutableSet, который сохраняет порядок вставки.Со их вики-страницы :

За исключением отсортированных коллекций, порядок сохраняется со времени создания. Например,

ImmutableSet.of("a", "b", "c", "a", "d", "b")

будет перебирать свои элементы в порядке "a", "b", "c", "d".

0 голосов
/ 02 ноября 2016

У меня была похожая проблема, поэтому я написал свою.Смотрите здесь .IndexedArraySet расширяет ArrayList и реализует Set, поэтому он должен поддерживать все необходимые вам операции.Обратите внимание, что вставка элементов в местоположения в середине ArrayList может быть медленной для больших списков, поскольку все следующие элементы необходимо переместить.Мой IndexedArraySet не меняет этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...