Java hashtable clé à deux éléments

[Résolu/Fermé]
Signaler
Messages postés
7
Date d'inscription
samedi 3 décembre 2011
Statut
Membre
Dernière intervention
4 décembre 2011
-
Messages postés
16400
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
21 septembre 2021
-
Bonjour,

Je suis en ce moment entrain de travailler sur un projet de programmation à la fac, qui consiste à mettre en réseau des aquariums.

chaque utilisateur pouvant créer plusieurs objets, chaque objet a un champ userID et itemID afin de pouvoir etre repéré facilement.

dans mon serveur, pour stocker ces objets, j'ai souhaité utiliser une table de hachage, parce que je pensais que c'était super pratique de pouvoir accéder directement à un objet par une clé qui serait représentée par ses deux ID.

voila mon code :

 public static void createItems(){ 

  int i; //à garder pour creer des IDs différentes 

  StoneFactory sf = new StoneFactory(); 
  SeaweedFactory swf = new SeaweedFactory(); 

  Integer cle[] =new Integer[2]; //contient l'userID et l'itemID 
  for (i=0 ; i< NB_STONE ; i++){ 
   Stone s = sf.newItems(i, myID);  
   sf.sink(items.values(), s); //pour éviter que deux objets se superposent 
   cle[0]=i; 
   cle[1] = myID; //ID du serveur 
   items.put(cle, s); 
  } 
  for (int j= i ; j-i< NB_SEAWEED ; j++){ //idem pour les algues 
   Seaweed sw = swf.newItems(j, myID); 
   swf.sink(items.values(), sw); 
   cle[0]=j; 
   cle[1] = myID; 
   items.put(cle, sw); 
  } 

 }



mais voila, je me suis rendu compte qu'au final, ce qui servait de clé ce n'était pas le contenu de ma clé, mais son adresse, et résultat ma table ne contient qu'un élément.

Je n'ai pas réussit à trouver dans la doc ni sur google comment faire pour avoir une clé à partir de deux entiers, avez vous une idée ?


meme si je mets le " Integer cle[] =new Integer[2];" à l'intérieur des boucles, je ne vais pas pouvoir me servir de ma table de hachage parce que je ne pourrai pas repérer un item par ses IDs

5 réponses

Messages postés
16400
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
21 septembre 2021
2 879
Tu pourrais faire deux HashMap<Integer,Stone> la première avec les userID comme clé, la deuxième avec les itemID. À moins que tes entiers soient très différent (aucun userID commun avec les itemID) auquel cas tu peux carrément tout mettre dans la même map.

Remarque : Les objets Stone ne seront pas copiés puisqu'on ne manipule que les références, ça reste donc assez souple en mémoire.

Tu peux bien sûr te créer une petite classe pour manipuler tes map et être sûr d'être cohérent dans la manipulation de tes données.

class doubleMap
{
     private final HashMap<Integer,Stone> mapUser;
     private final HashMap<Integer,Stone> mapItem;

     public boolean put(Integer userID,Integer itemID,Stone s)
     {
          return mapUser.add(userID,s) && mapItem.add(itemID,s);
     }

     public Stone getUser(Integer userID)
     {
          return mapUser.get(userID);
     }

     public Stone getItem(Integer itemID)
     {
          return mapItem.get(itemID);
     }
}
Messages postés
7
Date d'inscription
samedi 3 décembre 2011
Statut
Membre
Dernière intervention
4 décembre 2011

Bonsoir KX,

Si un meme utilisateur ajoute deux pierres, elles auront un itemID différent, mais le meme userID. Inversement, si deux utilisateurs ajoutent une pierre, elles auront un userID différent, mais rien ne garanti qu'elles n'auront pas le meme itemID.

Je ne peux donc pas envisager cette solution :/
Messages postés
16400
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
21 septembre 2021
2 879
Bon j'avoue que je n'avais pas forcément bien compris le problème ^^

Alors peut-être que tu peux utiliser une HashMap<Identifiant,Stone> avec :

class Identifiant
{
    private final int user;
    private final int item;
    
    public Identifiant(int userID,int itemID)
    {
        user=userID;
        item=itemID;
    }

    @Override
    public boolean equals(Object obj)
    {
         if (obj instanceof Identifiant)
         {
              Identifiant id = (Identifiant) obj;
              return id.user==user && id.item==item;
         }
         else return false;
    }

    @Override
    public int hashCode()
    {
        return user*item; // par exemple
    }
}
Messages postés
7
Date d'inscription
samedi 3 décembre 2011
Statut
Membre
Dernière intervention
4 décembre 2011

J'ai bien pensé à un truc comme ça, mais je ne vois pas de hashCode permettant de distinguer à coup sur un couple.

Par exemple là, la clé (2,1) est la meme que la clé (1,2), ce que je en veux pas.

C'est d'autant plus difficile que l'itemID est donné par le client. et ce n'est pas forcément moi qui code le client, les projets de tous ceux de ma promo doivent pouvoir se connecter à mon serveur, donc mon hashCode doit etre sûr
Messages postés
7
Date d'inscription
samedi 3 décembre 2011
Statut
Membre
Dernière intervention
4 décembre 2011

http://www.bouleis.fr/public/Compilation/javadoc/share/Couple.html

cette classe serait parfaite, mais elle n'a pas l'air d'exister "en vrai" (eclipse ne sait pas faire d'import pour cette classe)
Messages postés
16400
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
21 septembre 2021
2 879
Une classe Couple c'est exactement ce que j'ai fait tout à l'heure...

Si le hashCode est identique pour deux identifiants différents la méthode equals est appelé, donc ce n'est pas un problème pour (1,2) et (2,1), parce qu'après on aura 1==2 && 2==1 qui donnera false.
Du coup les deux identifiants seront différents tu n'as pas à t'en faire pour ça.

L'intérêt du hashCode est de comparer deux identifiants de manière plus rapide que l'appel de equals. En fait user*item comme je l'ai fait tout à l'heure c'est trop compliqué pour être vraiment intéressant. il vaudrait mieux faire un hashCode qui retourne juste user (ou item) comme ça si les deux users sont identiques on appelle equals pour comparer user ET item (donc on aura fait 3 comparaisons), mais en général on les deux users sont différents avec le hashCode on n'aura comparé que l'user (et donc fait 1 seule comparaison). En moyenne on fait donc moins de 2 comparaisons c'est plus rapide. Après à toi de voir s'il est plus intéressant de mettre user ou item pour qu'on appelle le moins souvent equals. Mais tout ceci ce n'est que de l'optimisation, ça ne change rien au fait que de toute façon le hashCode est complété par equals.
Messages postés
7
Date d'inscription
samedi 3 décembre 2011
Statut
Membre
Dernière intervention
4 décembre 2011

aaaah génial, je vais essayer ça alors, je n'avais pas compris que les clés fonctionnaient comme ça !

Merci !
Messages postés
7
Date d'inscription
samedi 3 décembre 2011
Statut
Membre
Dernière intervention
4 décembre 2011

je viens de faire le test, et ça fonctionne très bien, je te remercie vraiment beaucoup !
Messages postés
16400
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
21 septembre 2021
2 879
Remarque : en y repensant il serait peut-être mieux d'utiliser une map de type ConcurrentHashMap<Integer,ConcurrentHashMap<Integer,Stone>>
Concurrent, c'est parce que tu vas être sur ton serveur et que plusieurs personnes pourraient y accéder en même temps. Et l'imbrication des deux c'est pour t'éviter ton type couple, et la manipulation du hashCode, parce qu'en fait si il y a beaucoup de hashCode identiques tu risque de faire beaucoup de tests equals et perdre en efficacité.
Du coup on considère que chaque utilisateur a sa propre HashMap où l'on récupère les item.

Stone put(Integer userID,Integer itemID,Stone s)
{
	if (!map.contains(userID))
		map.put(userID,new ConcurrentHashMap<Integer,Stone>());
	
	return map.get(userID).put(itemID,s);
}

Stone get(Integer userID,Integer itemID)
{
	if (!map.contains(userID))
		return null;
	else
		return map.get(userID).get(itemID,s);
}
Messages postés
7
Date d'inscription
samedi 3 décembre 2011
Statut
Membre
Dernière intervention
4 décembre 2011

C'est gentil mais maintenant que ça marche, je n'ai plus le temps de tout modifier, je dois rendre mon projet à la fin de la semaine et je suis loin d'avoir fini ;)
Messages postés
16400
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
21 septembre 2021
2 879
Comme tu veux. Pour un projet futur peut-être ;-)