Чи існує набір для збереження порядку вставки, який також реалізує List?


85

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

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


Ви маєте на увазі зберегти порядок їх вставки або якийсь порядок, визначений символом Comparator? Також вам потрібна семантика Listінтерфейсу?

Відповіді:


207

TreeSetсортується за порядком елементів; LinkedHashSetзберігає порядок вставки. Сподіваємось, одним із таких є те, що ви шукали.

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

Крім того, спільні колекції Apache4 пропонують ListOrderedSetі SetUniqueList, які поводяться однаково і повинні відповідати заданим вимогам.



12

Ви маєте на увазі подобається 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;
    }
}

Він не реалізує Listінтерфейс, див. Мої зміни до запитання
yegor256

2
stackoverflow.com/a/8185105/253468 виглядає краще, оскільки він не має O(n)складності вставки, є компроміс, який слід враховувати між подвійним зберіганням та O(log(n))операцією вставки.
TWiStErRob

8

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

Хеш-код набору визначається як сума хеш-кодів елементів у наборі, де хеш-код нульового елемента визначається рівним нулю.

З іншого боку, ось договір List.hashCode:

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

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

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



0

У мене була подібна проблема, тому я написав свою. Дивіться тут . IndexedArraySetПоширюється ArrayListі інвентар Set, тому він повинен підтримувати всі операції , які вам потрібні. Зверніть увагу, що вставка елементів у місця розташування в середині an ArrayListможе бути повільною для великих списків, оскільки всі наступні елементи потрібно перемістити. Моє IndexedArraySetце не змінює.


0

Іншим варіантом (за винятком Listвимог щодо інтерфейсу) є Guava ImmutableSet, який зберігає порядок вставки. З їхньої вікі-сторінки :

За винятком відсортованих колекцій, порядок зберігається від часу будівництва. Наприклад,

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

буде здійснювати ітерацію над її елементами в порядку "a", "b", "c", "d".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.