[Java] Hashset und arrays (doppelte Einträge)

Dieses Thema im Forum "Programmierung & Entwicklung" wurde erstellt von Coksnuss, 23. Januar 2011 .

Status des Themas:
Es sind keine weiteren Antworten möglich.
  1. 23. Januar 2011
    Hashset und arrays (doppelte Einträge)

    'n Abend / Morgen,

    Und zwar habe ich folgendes Problem:

    Gegeben ist folgende Variable (java.util)
    Code:
    Set<int[]> setOfTuples;
    Diese habe ich folgender maßen initialisiert:
    Code:
    setOfTuples = new HashSet<int[]>();
    Und fülle sie mit Werten:
    Code:
    public void add(int a, int b)
    {
     int[] tuple = { a , b };
     setpOfTuples.add (tuple);
    }
    
    add(1, 1);
    add(1, 1);
    
    Leider enthalt mein setOfTuples jetzt 2 gleich array (was den Sinn eines Sets ja verfehlt). Meine Frage ist also: Was wäre eine Lösung für dieses Problem (ich muss mit Set<int[]> arbeiten).

    Besten Dank schonmal für die Hilfe.
     
  2. 23. Januar 2011
    AW: Hashset und arrays (doppelte Einträge)

    normalerweise kenn ich das so, dass die Add()-Methode von Hashsets autoamtische Dublikate findet und nur etwas einfügt, wenn der Wert noch nicht drin steht.

    Vielleicht funktioniert das mit Arrays nicht mehr.

    Du könntest mal probieren in deiner Add-Methode den Befehl setpOfTuples.contains(tuple) zu benutzen, um zu überprüfen, ob die Abfrage nach doppelten Array-Einträgen funktioniert.
    -> Am Besten vor dem HashSet-Add mit einer Ausgabe.

    Ansonsten wüsste ich nur noch jeden HashSet-Eintrag -> jedes Element des Eintrags mit a,b zu vergleichen.
     
  3. 23. Januar 2011
    AW: Hashset und arrays (doppelte Einträge)

    int[]-Arrays sind im eigentlichen Sinne keine primitiven Datentypen mehr (wie z.B. int). int[]-Arrays erweitern nämlich java.lang.Object.
    Und bei Objekten kann man die Gleichheit nicht mehr so einfach feststellen.
    1. "Identitätsgleichheit": Objekt1 und Objekt2 verweisen auf die selbe Stelle im Speicher
    2. "Wertgleichheit": Alle Instanzvariablen der Objekte stimmen überein
    Während man Punkt 1) sehr einfach testen kann (schon mit dem "=="-Operator), muss man bei Punkt 2) ja irgendwie "händisch" alle Instanzvariablen vergleichen. Das geschieht mit den Methoden equals(Object obj) und hashCode() (beide bereits in java.lang.Object implementiert (siehe Doku).
    Wenn Du allerdings 2 wertgleiche int[]-Arrays via hashCode() vergleichst (genau das macht auch HashSet), wirst Du verschiedene Hashes erhalten:
    PHP:
            int []  one  = { 1 1 };
            
    int []  two  = { 1 1 };
            
            
    System . out . println ( one . hashCode () +  " ungleich "  two . hashCode ());
            
    // gibt: "4072869 ungleich 1671711"
    Und HashSet arbeitet mit der hashCode()-Methode: Source-Code von HashSet
    Genauer gesagt macht die Überprüfung HashMap .put().


    Und da dabei, wie gesagt, verschiedene Hashwerte herauskommen, kann die HashMap 2 int[]-Arrays nur auf identitätsgleichheit prüfen:
    PHP:
            HashSet < int []>  set  = new  HashSet < int []>();
            
            
    int []  one  = { 1 1 };
            
    int []  two  = { 1 1 };
            
            
    set . add ( one ); set . add ( one );
            
    // liefert 1
            
    System . out . println ( set . size ());
    PHP:
            HashSet < int []>  set  = new  HashSet < int []>();
            
            
    int []  one  = { 1 1 };
            
    int []  two  = { 1 1 };
            
            
    set . add ( one ); set . add ( two );
            
    // liefert 2
            
    System . out . println ( set . size ());
    Sobald man also mit Collections arbeitet, die auch wertegleiche Objekte erkennen soll, sollte man immer die Methoden equals(Object obj) und hashCode() entsprechend überschreiben.

    Aber das geht ja leider nicht bei den nativen int[]-Arrays.
    Falls Du wirklich mit ihnen arbeiten musst, könntest Du ja HashSet ableiten, und dort die add()-Methode überschreiben bzw Deine eigene add()-Methode anpassen.
    Die Variablendeklaration Set<int[]> setOfTuples; hättest Du dann ja nicht verletzt, könntest aber beispielsweise via java.util.Arrays.equals(o1, o2) prüfen, ob es sich bei dem neu einzufügenden Array um ein Duplikat handelt.

    @ b-xXx
    contains() wird dabei auch nicht helfen, da es auch nur auf die equals() verweist. Selbes Problem also. Daher sollte man dafür zB java.util.Arrays nutzen.

    --
    So, ich hoffe, dass es einigermaßen verstänlich war und ich helfen konnte ^^
     
  4. 23. Januar 2011
    AW: Hashset und arrays (doppelte Einträge)

    Wie meine Vorposter schon sagten, funktioniert das mit Arrays nicht richtig.

    Das Set ruft beim adden die equals() Methode auf, die bei den Arrays jedoch immer false returned.

    Ich weiß nicht, ob das die schönste Lösung ist, aber eine Idee wäre eine eigene Klasse zu schreiben, die z.B. Array Implementiert und die equals() und hashCode() Methoden zu überschreiben (siehe auch hier)




    Eine andere Dirty-Lösung wäre folgende:
    Code:
    
    public void add(int a, int b)
    {
     Integer[] tuple = { a , b };
     for(Integer[] tmpInt : setpOfTuples){
     if(Arrays.equals(tmpInt, tuple){
     return;
     }
     }
     setpOfTuples.add (tuple);
    }
    
    add(1, 1);
    add(1, 1);
    
     
  5. 23. Januar 2011
    AW: Hashset und arrays (doppelte Einträge)

    Da du ja scheinbar nur Tuples aus zwei Elementen benötigst, schreib dir einfach eine Klasse, die die beiden Elemente hält und implementiere equals und hashCode selber.

    Damit funktioniert das Set dann auch wie gewünscht.
     
  6. 23. Januar 2011
    AW: Hashset und arrays (doppelte Einträge)

    Besten Dank Sn0wm4n für deinen ausführlichen Post, und auch an die anderen natürlich.

    Werde es jetzt entweder mit Vererbung machen oder als eigene Klasse (die hätte ggf. für meine Zwecke noch weitere Vorteile). Ich lass den Thread trotzdem mal offen für den Fall das jemand noch eine ultimative Idee hat - mir ist jedenfalls ausreichend geholfen.
     
  7. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.