2012-06-06 3 views
8

A HashSet<T> può determinare in O (1) se contiene un determinato elemento. Se sovrascrivo Equals() e GetHashCode() sulla mia classe personalizzata, posso avere un oggetto A e un altro oggetto A' che sono non uguale per identità, ma per i quali Equals() rendimenti true e GetHashCode() restituisce lo stesso codice hash.Ottenere un oggetto uguale da HashSet <T> in O (1)

Ora, dato che A è nel set di hash, voglio recuperare A in O (1) dato A '(che è uguale ad A dal punto di vista dell'hash set).

var a = new MyClass("A"); 
var a_prime = new MyClass("A"); 
Debug.Assert(a.Equals(a_prime)); 
Debug.Assert(a.GetHashCode() == a_prime.GetHashCode()); 

var set = new HashSet<MyClass>(); 
set.Add(a); 
Debug.Assert(set.Contains(a_prime)); 

// This:  
var retrieved_a = set.Get(a_prime); 

Come fare?

(Si noti che this non ha la risposta che sto cercando, e this non ha risposte a tutti.)


Alcune informazioni di base: Voglio utilizzare il set per stagista mia oggetti allo stesso modo C# interns stringhe: gli oggetti uguali hanno bisogno di una sola istanza. In questo modo posso aggiungere i metadati a un tale oggetto ed essere sicuro che non ci siano altre istanze uguali ovunque senza i metadati.

+6

Perché non utilizzare solo un dizionario che associa il 'A' a' A'? –

+0

possibile duplicato di [Come recuperare l'elemento effettivo da HashSet ?] (Http://stackoverflow.com/questions/7760364/how-to-retrieve-actual-item-from-hashsett) – nawfal

+0

Un altro [come accedere -le-riferimento valori-di-un-hashset-senza-censimento?] (http://stackoverflow.com/questions/7290443/how-to-access-the-reference-values-of-a-hashsettvalue-without -enumerazione?) – nawfal

risposta

7

Non esiste alcun metodo su HashSet che fa ciò che si desidera.

È possibile utilizzare un Dictionary invece:

var dict = new Dictionary<MyClass, MyClass>(); 
dict[a] = a; 
Debug.Assert(dict.ContainsKey(a_prime)); 
var retrieved_a = dict[a_prime]; 
+0

Ho sempre evitato di fare dicts che mappano a se stessi. Questa cattiva pratica? O mi sto solo preoccupando di nulla? –

+0

@Hans Come sempre, dipende. Perché pensi che sia una cattiva pratica? Perché li eviti? – svick

+3

@svick Non lo so, mi sembra strano. Immagino di non avere ragioni concrete per evitarlo, ma non ho mai dovuto usare un costrutto del genere, ma per qualche ragione guardare "dict [a] = a;" mi fa rabbrividire. –

1

Se ricordo bene, Dictionary non avere implementazioni di tempo costanti delle operazioni di set di base, mentre HashSet ha. Ecco un modo per implementarlo con una costante ricerca di uguale tempo, senza aumentare le altre complessità da HashSet. È fondamentale utilizzare questo approccio se è necessario acquisire molti elementi casuali. Quello che scrivo qui sotto è la sintassi Java, in quanto non conosco C#, ma l'idea è indipendente dalla lingua.

class MySet<A> { 
    ArrayList<A> contents = new ArrayList(); 
    HashMap<A,Integer> indices = new HashMap<A,Integer>(); 

    //selects equal element in constant time 
    A equalElement(A input) { 
     return contents.get(indices.get(input)); 
    } 

    //adds new element in constant time 
    void add(A a) { 
     indices.put(a,contents.size()); 
     contents.add(a); 
    } 

    //removes element in constant time 
    void remove(A a) { 
     int index = indices.get(a); 
     contents.set(index,contents.get(contents.size()-1)); 
     contents.remove(contents.size()-1); 
     indices.set(contents.get(contents.size()-1),index); 
     indices.remove(a); 
    } 

    //all other operations (contains(), ...) are those from indices.keySet() 
} 
+0

Scusa, il random era un refuso, intendevo uguale invece che casuale. Ho corretto il metodo ora. Fondamentalmente, invece di usare un HashSet, utilizzo un HashMap * e * un ArrayList, contenente gli stessi elementi e con HashMap che punta agli indici di quell'elemento in ArrayList. Invece del semplice "Sì, ho già questa chiave" da HashSet, HashMap dice "Sì, ho già questa chiave e punta all'intero' i' ". Quindi in ArrayList puoi recuperare il tuo oggetto prendendo l'oggetto in posizione 'i'. – user1111929

+0

Grazie per le correzioni!Ora è molto più rilevante! Come nota a margine, sarei ancora molto attento a questa affermazione a "tempo costante". Non penso che HashMaps abbia garantito il tempo di recupero del caso peggiore O (1), penso che sia medio-O (1), e tu puoi ottenere molto peggio se tu, ad esempio, armeggi male con GetHashCode delle chiavi della mappa. In ogni caso, rimosso -1 e il commento precedente, in quanto non corrisponde al post come è ora. – quetzalcoatl

+0

Hai ragione, con "tempo costante" intendevo "tempo medio: costante". – user1111929

Problemi correlati