2013-05-20 11 views
8

Sto cercando di creare una serie di array di interi, la cosa è che se provo a fare:Aggiunta di array con gli stessi valori per HashSet risultati in elementi duplicati

HashSet<int[]> s = new HashSet<int[]>(); 
int a1[] = {1,2,3}; 
int a2[] = {1,2,3}; 
s.add(a1); 
s.add(a2) 
System.out.println(s.size()); 

Poi s ha due oggetti, ma dovrebbe essercene solo uno. Nota: non importa se è HashSet < Integer []>. Semplicemente non funziona.

Ora se cerco di farlo con un ArrayList < intero>, qualcosa di simile:

HashSet<ArrayList<Integer>> s = new HashSet<ArrayList<Integer>>(); 
ArrayList<Integer> a1 = new ArrayList<Integer>(); 
ArrayList<Integer> a2 = new ArrayList<Integer>(); 
a1.add(1); 
a1.add(2); 
a1.add(3); 

a2.add(1); 
a2.add(2); 
a2.add(3); 

s.add(a1); 
s.add(a2) 
System.out.println(s.size()); 

Poi s ha un oggetto.

ho però un modo per evitare l'errore nel primo codice e stava memorizzando codici hash di ciascuna matrice in una hashset come segue:

int a1[] = {0,10083,10084,1,0,1,10083,0,0,0,0}; 
int a2[] = {1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0,2112}; 
HashSet<Integer> s= new HashSet<Integer>();//hashcodes of each array 
s.add(Arrays.hashCode(a1)); 
s.add(Arrays.hashCode(a2)); 
System.out.println(Arrays.hashCode(a1)); 
System.out.println(Arrays.hashCode(a2)); 
System.out.println(s.size()); 

Funziona per il primo caso (1,2,3) ma nei casi in cui ci sono collisioni non funziona, quindi dovrei gestire le collisioni. Quindi, penso che quello che sto facendo sia implementare un HashSet da solo.

Con HashSet < ArrayList < Integer >> funziona perfettamente. Suppongo che java gestisca le collisioni in quel caso.

mia domanda è perché Java non permette di gestire un int HashSet < []> o HashSet < Integer []> se codici hash generati sono gli stessi in ArrayList < Integer> e codici hash di array possono essere calcolati semplicemente chiamando il numero Arrays.hashCode (...).

E infine, se voglio fare un HashSet < int []> (o HashSet < Integer []>) Dovrei implementarlo da solo? O c'è un modo migliore per farlo?

Grazie.

UPDATE: Ok, finalmente penso di aver trovato una risposta completa. Come @ZiyaoWei e @ user1676075 hanno commentato che non funziona perché equals restituisce false e gli hashcode sono diversi. Ma, perché java non sovrascrive questo metodo (con Arrays.equals(), Arrays.hashCode()) così si può fare qualcosa come HashSet < int []>? La risposta è perché un array è un oggetto mutabile e hashcode non può dipendere da valori mutabili (ogni elemento dell'array è un valore mutabile) in base al contratto generale di hashcode. Mutable objects and hashCode

Qui piacevoli spiegazioni di utilizzare i campi mutabili in hashCode http://blog.mgm-tp.com/2012/03/hashset-java-puzzler/ e le chiavi mutevoli in HashMaps Are mutable hashmap keys a dangerous practice?

La mia risposta è, se si desidera utilizzare un int HashSet < []> Si deve creare una classe che ha un array e se si desidera che l'hashcode e sia uguale a dipendere dai valori, eseguire l'override dei metodi equals() e hashCode() con Arrays.equals() e Arrays.hashCode(). Se non vuoi violare il contratto, rendi l'array definitivo.

Grazie a tutti!

+0

Vedere la risposta di Ziyao sotto. In breve, controlla se a.hashCode() corrisponde a b.hashCode(). Scommetto che non sono uguali. –

+0

possibile duplicato di [come creare un set di array in java?] (Http://stackoverflow.com/questions/9841934/how-to-make-a-set-of-array-in-java) – Raedwald

risposta

8

Non ha nulla a che fare con collisione alla fine della giornata:

a1.equals(a2) == false 

Dal momento che non sono uguali, un Set li tratteranno come diversi.

Nota: Array in Java non sovrascrive il metodo equals da Object.

E poiché add in Set è definito come

Più formalmente, aggiunge l'elemento specificato e per questo insieme se il set non contiene e2 elementi tali che (e == null e2 == null:? E .equals (E2))

è sembra essere impossibile da attuare correttamente un Set che potrebbe soddisfare la vostra richiesta (confrontare gli elementi con Arrays.equals) senza violare alcuni contratti.

+0

Mi sento come questo è un difetto in Java. 'Array' dovrebbe escludere' equals' dal mio punto di vista. Non riesco a trovare un riferimento in Java efficace che spiega perché non lo fa. –

+0

@PhilipWhitehouse Concordato, e non riesco a trovare nulla che spiega l'argomento sia. –

+0

Ciao, grazie. Penso che sia collegato alle collisioni. Quando si desidera utilizzare un HashSet , è necessario eseguire l'override dei metodi hashCode e equals. Perché se ha lo stesso hashcode, allora deve usare il metodo di uguaglianza per vedere se sono uguali o meno (come so, correggimi se sbaglio per favore!). Penso che tu abbia ragione, è perché java non sovrascrive il metodo equals per gli array. :) – voodoo14

1

Il motivo per cui HashSet> funziona è perché HashSet utilizzerà il confronto .equals() per decidere se si sta inserendo lo stesso oggetto due volte. Nel caso di List, due elenchi dello stesso tipo di base (ad esempio ArrayList) con lo stesso contenuto, nello stesso ordine, verranno confrontati come uguali. Quindi stai dicendo al HashSet di inserire lo stesso oggetto due volte. Richiede solo una singola istanza una volta.

Quando si tenta di eseguire la stessa operazione con un array. Vedi questo post: equals vs Arrays.equals in Java per ulteriori dettagli sui confronti di array in Java. Quando si inseriscono due array, il test .equals() predefinito verifica se sono lo stesso oggetto, che non sono. Quindi fallisce.

Problemi correlati