IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

avec Java Discussion :

HashSet et doublons


Sujet :

avec Java

  1. #1
    Membre éclairé
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Juin 2008
    Messages
    522
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Chercheur en informatique

    Informations forums :
    Inscription : Juin 2008
    Messages : 522
    Points : 725
    Points
    725
    Par défaut HashSet et doublons
    Bonjour,
    Je constate dans mon code une chose bizarre,
    J'ai crée une classe avec les membres hashCode et equals,
    Ensuite j'ai une classe Instruction sans equals ou hashCode
    Puis je définis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Set<Pair<String, Pair<Set<Integer>, Instruction>>> varWrite=new HashSet<...>()
    Ensuite j'insert des élément dedans, et comme j'ai une boucle infinie je regarde le set avec le code suivant (en bref j'imprine les hashs et je compare les éléments 2 à 2)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for(Pair<String, Pair<Set<Integer>, Instruction>> entry:varWrite )
            System.out.print("|"+entry.hashCode());
    System.out.println();
    Pair<String, Pair<Set<Integer>, Instruction>> preventry=null;
    for(Pair<String, Pair<Set<Integer>, Instruction>> entry:varWrite )
    {
            System.out.print("|"+entry.equals(preventry));
            preventry=entry;
    }
    System.out.println();
    Si j'ai bien compris mon Set utilise equals, ne contient pas de doublons et donc ici je devrais voir false partout, seulement voilà non seulement les hashs sont pour la plupart égaux mais aussi les .equals renvoient true.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    |-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|-495702225|...495702225|1086338479|1086338479|1086338479|1086338479|1086338479|1086338479|1086338479|1086338479|1086338479|1086338479|1086338479|...|1086338479
    |false|true|true|true|true|true|true|true|true|true|true|...|true|true
    D'où ma question, pourquoi ai-je des doublons dans mon set ?

    Cordialement

  2. #2
    Membre chevronné
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Donne nous le code de equals et de hashSet, et on te dira ce qui ne va pas

    Régle à connaitre :
    deux objets égaux ont le même hashset
    deux objets qui ont le même hashset ne sont pas forcement égaux
    deux objets différents peuvent avoir le même hashset

  3. #3
    Membre éclairé
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Juin 2008
    Messages
    522
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Chercheur en informatique

    Informations forums :
    Inscription : Juin 2008
    Messages : 522
    Points : 725
    Points
    725
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class Pair<U, V> {
        private U first;
        private V second;
     
        public Pair(U u,V v){first=u;second=v;}
     
        public U getFirst(){return first;}
        public V getSecond(){return second;}
     
        public String toString()
        {
            return "("+first+","+second+")";
        }
     
        public boolean equals(Object p2)
        {
            if(p2 instanceof Pair<?,?>)
            {
                Pair<U,V> p=(Pair<U,V>)p2;
                return first.equals(p.first)&&second.equals(p.second);
            }
            return false;
        }
     
        public int hashCode() {
            int hashFirst = first != null ? first.hashCode() : 0;
            int hashSecond = second != null ? second.hashCode() : 0;
     
            return (hashFirst + hashSecond) * hashSecond + hashFirst;
        }
    }

  4. #4
    Membre chevronné
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Pourquoi un truc aussi compliqué que ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return (hashFirst + hashSecond) * hashSecond + hashFirst;
    Ici, si first est null, ca équivaut à renvoyer hashSecond², et si second est null, ça renvoie hashFirst.
    Si les deux sont null ça renvoie 0

    Un retour comme celui-là devrait suffire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return (hashFirst + hashSecond);


    Par contre, ton equals et ton hashcode ne sont pas cohérents : dans le hashcode, first et second peuvent tous les deux être null, mais le equals impose qu'ils ne le soient jamais (sinon PAF)

    De plus, tu n'es pas obligé de typer Pair :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
            if(p2 instanceof Pair) {
                Pair p=(Pair)p2;
                return first.equals(p.first)&&second.equals(p.second);
            }
    Tu as le hashCode et equals de ta classe Instruction?

  5. #5
    Modérateur
    Avatar de kolodz
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    2 211
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 211
    Points : 8 316
    Points
    8 316
    Billets dans le blog
    52
    Par défaut
    Citation Envoyé par eulbobo Voir le message
    Pourquoi un truc aussi compliqué que ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return (hashFirst + hashSecond) * hashSecond + hashFirst;
    Ici, si first est null, ca équivaut à renvoyer hashSecond², et si second est null, ça renvoie hashFirst.
    Si les deux sont null ça renvoie 0

    Un retour comme celui-là devrait suffire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return (hashFirst + hashSecond);
    Cela est pour ne pas avoir de colision de hash trop facilement. Si tes classes retourne leur ID entant que hash (ce qui est totalement possible).
    Si hash1 = 2 et Hash2 =3 alors, le hash est égale à hash1=1 et hash2=4.
    Même si cela n'est pas un problème en soit. Il est préférable d'ajouter de l'entropie dans le Hash.

    Pour information, il y a pas mal de fonction de hash dans le code de l'API standard qui ont cette forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // Class TreeMap
            public int hashCode() {
                int keyHash = (key==null ? 0 : key.hashCode());
                int valueHash = (value==null ? 0 : value.hashCode());
                return keyHash ^ valueHash;
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // Class LocalDateTime
        /**
         * A hash code for this date-time.
         *
         * @return a suitable hash code
         */
        @Override
        public int hashCode() {
            return date.hashCode() ^ time.hashCode();
        }
    Cordialement,
    Patrick Kolodziejczyk.

  6. #6
    Membre chevronné
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Je ne pense pas qu'il en soit à un niveau qui requiert de l'optimisation de la répartition des clés de hachage.

  7. #7
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par eulbobo Voir le message
    Je ne pense pas qu'il en soit à un niveau qui requiert de l'optimisation de la répartition des clés de hachage.
    +1

    Je pense que le problème vient plutôt du fait que sa classe "Pair" n'est pas immuable, du coup son hashCode peut changer après l'ajout ce qui "casse" complètement le fonctionnement du HashSet (et du HashMap).


    a++

  8. #8
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    +1 une clé doit être immutable. Ca n'explique pas la boucle infinie (et où elle est d'ailleurs?) mais en tout cas ça rends Pair inutilisable comme clé d'un Set ou d'une Map

  9. #9
    Membre éclairé
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Juin 2008
    Messages
    522
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Chercheur en informatique

    Informations forums :
    Inscription : Juin 2008
    Messages : 522
    Points : 725
    Points
    725
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Salut,


    +1

    Je pense que le problème vient plutôt du fait que sa classe "Pair" n'est pas immuable, du coup son hashCode peut changer après l'ajout ce qui "casse" complètement le fonctionnement du HashSet (et du HashMap).


    a++
    Effectivement, je pense que le problème vient de là, merci

  10. #10
    Modérateur
    Avatar de kolodz
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    2 211
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 211
    Points : 8 316
    Points
    8 316
    Billets dans le blog
    52
    Par défaut
    Citation Envoyé par eulbobo Voir le message
    Je ne pense pas qu'il en soit à un niveau qui requiert de l'optimisation de la répartition des clés de hachage.
    Non, mais tu donne des conseils sur les Hash qui ne sont pas bon. Cela mériterai d'être souligner.

  11. #11
    Membre chevronné
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Citation Envoyé par kolodz Voir le message
    Non, mais tu donne des conseils sur les Hash qui ne sont pas bon. Cela mériterai d'être souligner.
    Ma solution pour son hash était UNE solution qui n'était PAS MEILLEURE que la sienne : juste plus simple/lisible/compréhensible.
    Après, je le répète, il n'existe pas une seule solution pour calculer une clé de hachage et il y a des experts qui s'étripent pour savoir quelle est "la bonne".
    Utiliser un opérateur XOR n'est pas nécessairement une "bonne" solution non plus.

    La réponse est qu'il n'y a pas de bonne solution, parce que CA DEPEND de ce qu'on est en train de manipuler ET de comment on veut que ça se répartisse dans un Set. Accessoirement, son objet manipule des types génériques, donc impossible dans ce cas de déterminer une bonne formule étant donné que ça dépendra surtout des objets manipulés

    La seule mauvaise façon de coder un hashcode, c'est celle qui fait en sorte que le contrat entre hashCode et equals ne soit plus respecté.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Doublon au sein d'un HashSet
    Par amAtunisian dans le forum Collection et Stream
    Réponses: 6
    Dernier message: 24/04/2012, 11h35
  2. hashSet, collection et doublon
    Par Iceman Y15 dans le forum Collection et Stream
    Réponses: 6
    Dernier message: 18/10/2010, 14h40
  3. Ajout d'objet dans un HashSet (Doublon)
    Par gbinico dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 07/07/2008, 14h28
  4. [HashSet] C'est possible de mettre des doublons ! :-(
    Par Melchisedec dans le forum Collection et Stream
    Réponses: 1
    Dernier message: 27/07/2007, 11h15
  5. HashSet, probleme de doublon et parcour
    Par fusion_sadam dans le forum Langage
    Réponses: 5
    Dernier message: 23/05/2007, 15h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo