2011-11-18 11 views
77

Sto cercando di trovare un'implementazione di java.util.List e java.util.Set allo stesso tempo in Java. Voglio che questa classe permetta solo elementi unici (come Set) e conservi il loro ordine (come List). Esiste in JDK 6?Esiste un ordine di inserimento che preserva Set che implementa anche l'Elenco?

È importante avere List<T>#add(int, T) così posso inserirlo in una posizione specifica.

+0

Intendi conservare il loro ** inserimento ** ordine o un ordine definito da un 'Comparatore'? Vuoi anche la semantica dell'interfaccia 'Lista'? –

risposta

183

TreeSet è ordinato per ordine di elementi; LinkedHashSet conserva l'ordine di inserimento. Speriamo che uno di questi sia quello che cercavi.

Hai specificato che si desidera essere in grado di inserire in una arbitraria posizione , ho il sospetto che si dovrà scrivere il proprio - basta creare una classe che contiene un HashSet<T> ed un ArrayList<T>; quando aggiungi un oggetto, controlla se è presente nel set prima di aggiungerlo alla lista.

+0

Bene, il problema è che non ha il metodo 'List # add (int, T)'. – yegor256

+9

@ yegor256: Sarebbe stato utile se avessi detto prima ... modifica. –

10

Vuoi dire come LinkedHashSet? Ciò mantiene l'ordine di entrata, ma non consente duplicati.

IMHO, è un requisito insolito ma è possibile scrivere una lista 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; 
    } 
} 
+0

Non implementa l'interfaccia 'List', vedi le mie modifiche alla domanda – yegor256

+1

http://stackoverflow.com/a/8185105/253468 sembra migliore perché non ha la complessità di inserimento' O (n) ', c'è un compromesso si deve considerare tra doppia archiviazione e operazione di inserimento 'O (log (n))'. – TWiStErRob

5

Non si può implementare List e Set contemporaneamente senza la violazione del contratto. Vedere, per esempio, il Set.hashCode contratto:

Il codice hash di un insieme è definito come la somma dei codici hash degli elementi dell'insieme, in cui il codice hash di un elemento nullo è definita come zero.

D'altra parte qui è il contratto di List.hashCode:

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

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

Quindi è impossibile implementare una singola classe che garantisca che entrambi i contratti siano soddisfatti. Lo stesso problema per l'implementazione di equals.

0

Ho avuto un problema simile, quindi ho scritto il mio. Vedi here. Lo IndexedArraySet estende ArrayList e implementa Set, quindi dovrebbe supportare tutte le operazioni necessarie. Tieni presente che l'inserimento di elementi in posizioni nel mezzo di un ArrayList può essere lento per i grandi elenchi poiché è necessario spostare tutti i seguenti elementi. Il mio IndexedArraySet non lo cambia.

0

Un'altra opzione (meno il requisito List interfaccia) è ImmutableSet di Guava, che conserva ordine di inserimento. Da their wiki page:

Fatta eccezione per raccolta differenziata, ordine preservata da tempi di costruzione. Ad esempio,

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

sarà iterare suoi elementi nell'ordine "a", "b", "c", "d".

Problemi correlati