Esiste un set di conservazione dell'ordine di inserzione che implementa anche List?


85

Sto cercando di trovare un'implementazione di java.util.Liste java.util.Setallo stesso tempo in Java. Voglio che questa classe consenta solo elementi univoci (as Set) e conservi il loro ordine (come List). Esiste in JDK 6?

È importante averlo in List<T>#add(int, T)modo da poter inserire in una posizione specifica.


Intendi preservare il loro ordine di inserzione o un ordine definito da un Comparator? Vuoi anche la semantica Listdell'interfaccia?

Risposte:


207

TreeSetè ordinato in base all'ordine degli elementi; LinkedHashSetmantiene l'ordine di inserzione. Spero che uno di questi sia quello che stavi cercando.

Hai specificato che vuoi essere in grado di inserire in una posizione arbitraria , sospetto che dovrai scriverne uno tuo - crea semplicemente una classe contenente a HashSet<T>e an ArrayList<T>; quando si aggiunge un elemento, verificare se è presente o meno nel set prima di aggiungerlo all'elenco.

In alternativa, le commons-collections4 di Apache offrono ListOrderedSete SetUniqueList, che si comportano in modo simile e dovrebbero soddisfare i requisiti dati.



12

Intendi come LinkedHashSet? Ciò preserva l'ordine di immissione, ma non consente duplicati.

IMHO, è un requisito insolito ma puoi scrivere un elenco senza duplicati.

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;
    }
}

Non implementa l' Listinterfaccia, vedere le mie modifiche alla domanda
yegor256

2
stackoverflow.com/a/8185105/253468 ha un aspetto migliore perché non ha O(n)complessità di inserimento, c'è un compromesso da considerare tra la doppia memorizzazione e l' O(log(n))operazione di inserimento.
TWiStErRob

8

Non è possibile implementare Liste Setsubito senza violazione del contratto. Vedi, ad esempio, il Set.hashCodecontratto:

Il codice hash di un set è definito come la somma dei codici hash degli elementi nel set, dove il codice hash di un elemento null è definito come zero.

D'altra parte ecco il contratto di List.hashCode:

Il codice hash di una lista è definito come il risultato del seguente calcolo:

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

Quindi è impossibile implementare un'unica classe che garantisca l'adempimento di entrambi i contratti. Lo stesso problema per l' equalsimplementazione.



0

Ho avuto un problema simile, quindi ho scritto il mio. Vedi qui . Si IndexedArraySetestende ArrayListe implementa Set, quindi dovrebbe supportare tutte le operazioni di cui hai bisogno. Nota che l'inserimento di elementi in posizioni nel mezzo di un ArrayListpuò essere lento per elenchi di grandi dimensioni perché tutti gli elementi seguenti devono essere spostati. Il mio IndexedArraySetnon cambia questo.


0

Un'altra opzione (meno il Listrequisito dell'interfaccia) è Guava's ImmutableSet, che conserva l'ordine di inserimento. Dalla loro pagina wiki :

Fatta eccezione per le raccolte ordinate, l' ordine viene mantenuto dal momento della costruzione. Per esempio,

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

itererà sui suoi elementi nell'ordine "a", "b", "c", "d".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.