Czy istnieje zestaw zachowujący zamówienie reklamowe, który implementuje również listę?

85

Próbuję znaleźć implementację java.util.Listi java.util.Setjednocześnie w Javie. Chcę, aby ta klasa zezwalała tylko na unikalne elementy (as Set) i zachowywała ich kolejność (jak List). Czy istnieje w JDK 6?

Jest to ważne, aby List<T>#add(int, T)móc wstawić w określonej pozycji.

yegor256
źródło
Czy masz na myśli zachowanie ich kolejności reklamowej czy jakiegoś zamówienia określonego przez Comparator? Czy chcesz również poznać semantykę Listinterfejsu?

Odpowiedzi:

207

TreeSetjest sortowany według kolejności elementów; LinkedHashSetzachowuje zamówienie reklamowe. Mam nadzieję, że jednym z nich jest to, czego szukałeś.

Określiłeś, że chcesz mieć możliwość wstawiania w dowolnym miejscu, podejrzewam, że będziesz musiał napisać własną - po prostu utwórz klasę zawierającą a HashSet<T>i ArrayList<T>; dodając element, sprawdź, czy znajduje się w zestawie przed dodaniem go do listy.

Alternatywnie, oferowane przez Apache wspólne kolekcje4 ListOrderedSeti SetUniqueList, które zachowują się podobnie i powinny spełniać podane wymagania.

Jon Skeet
źródło
12

Czy masz na myśli jak LinkedHashSet? To zachowuje kolejność wpisów, ale nie zezwala na duplikaty.

IMHO, to niezwykłe wymaganie, ale możesz napisać listę bez duplikatów.

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;
    }
}
Peter Lawrey
źródło
Nie implementuje Listinterfejsu, zobacz moje zmiany w pytaniu
yegor256
2
stackoverflow.com/a/8185105/253468 wygląda lepiej, ponieważ nie ma O(n)złożoności wstawiania, istnieje kompromis, który należy rozważyć między podwójnym przechowywaniem a O(log(n))operacją wstawiania.
TWiStErRob
8

Nie możesz wdrożyć Listi Setod razu bez naruszenia umowy. Zobacz na przykład Set.hashCodeumowę:

Kod skrótu zestawu jest zdefiniowany jako suma kodów skrótu elementów w zestawie, gdzie kod skrótu elementu zerowego jest zdefiniowany jako zero.

Z drugiej strony oto umowa List.hashCode:

Kod skrótu listy jest zdefiniowany jako wynik następującego obliczenia:

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

Nie można więc zaimplementować jednej klasy, która gwarantuje wykonanie obu umów. Ten sam problem do equalsrealizacji.

Tagir Valeev
źródło
4

Jeśli nie ograniczysz się do JDK 6, możesz skorzystać z biblioteki wspólnych kolekcji Apache, która oferuje dokładne dopasowanie do Twoich potrzeb - ListOrderedSet . To jest jak Listi Setpołączone razem :)

Ondrej Bozek
źródło
bez Listinterfejsu
LateralFractal,
0

Miałem podobny problem, więc napisałem własny. Zobacz tutaj . IndexedArraySetRozciąga ArrayListi narzędzia Set, dlatego należy wspierać wszelkie działania, które są potrzebne. Zwróć uwagę, że wstawianie elementów do lokalizacji w środku ArrayListmoże być powolne w przypadku dużych list, ponieważ wszystkie kolejne elementy muszą zostać przeniesione. Mój IndexedArraySetnie zmienia tego.

JanKanis
źródło
0

Inną opcją (bez Listwymogu interfejsu) jest Guava ImmutableSet, która zachowuje kolejność reklam. Z ich strony wiki :

Poza kolekcjami posortowanymi zachowany jest porządek od czasu budowy. Na przykład,

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

będzie iterował po swoich elementach w kolejności „a”, „b”, „c”, „d”.

kuporific
źródło