web-dev-qa-db-fra.com

Table de hachage à valeurs multiples dans Java

Est-il possible d'avoir plusieurs valeurs pour la même clé dans une table de hachage? Sinon, pouvez-vous suggérer une telle classe ou interface qui pourrait être utilisée?

25
raji

Non, c'est un peu l'idée des tables de hachage.

Cependant, vous pouvez soit lancer le vôtre avec un Map<YourKeyObject, List<YourValueObject>> et quelques méthodes utilitaires pour créer la liste si elle n'est pas présente, ou utilisez quelque chose comme Multimap from Google Collections .

Exemple:

String key = "hello";
Multimap<String, Integer> myMap = HashMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // prints either "[1, 5000]" or "[5000, 1]"
myMap = ArrayListMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // always prints "[1, 5000]"

Notez que Multimap n'est pas un équivalent exact de la solution maison; Hashtable synchronise toutes ses méthodes, tandis que Multimap n'offre aucune garantie de ce type. Cela signifie que l'utilisation d'un Multimap peut vous poser des problèmes si vous l'utilisez sur plusieurs threads . Si votre carte n'est utilisée que sur un seul thread, cela ne fera aucune différence (et vous auriez dû utiliser HashMap au lieu de Hashtable de toute façon).

21
Michael Myers

Les valeurs d'une table de hachage sont Object afin que vous puissiez stocker une liste

11
Eric

Dans une table de hachage, on utiliserait une paire clé/valeur pour stocker des informations.

En Java, la classe Hashtable accepte une seule valeur pour une seule clé. Voici un exemple de tentative d'association de plusieurs valeurs à une seule clé:

Hashtable<String, String> ht = new Hashtable<String, String>();

ht.put("Answer", "42");
ht.put("Hello", "World");    // First value association for "Hello" key.
ht.put("Hello", "Mom");      // Second value association for "Hello" key.

for (Map.Entry<String, String> e : ht.entrySet()) {
  System.out.println(e);
}

Pour essayer d'inclure plusieurs valeurs ("World", "Mom") sur une seule touche ("Hello"), on se retrouve avec le résultat suivant pour l'impression des entrées dans le Hashtable:

Answer=42
Hello=Mom

La paire clé/valeur de "Hello" et "World" n'est pas dans le Hashtable - seulement le deuxième "Hello" et "Mom" se trouvent dans Hashtable. Cela montre que l'on ne peut pas avoir plusieurs valeurs associées à une seule clé dans un Hashtable.


Ce qui est vraiment nécessaire ici est un multimap , qui permet une association de plusieurs valeurs à une seule clé.

Une implémentation du multimap est Multimap de Google Collections :

Multimap<String, String> mm = HashMultimap.create();

mm.put("Answer", "42");
mm.put("Hello", "World");
mm.put("Hello", "Mom");

for (Map.Entry<String, String> e : mm.entries()) {
  System.out.println(e);
}

Ceci est similaire à l'exemple ci-dessus qui utilisait Hashtable, mais le comportement est assez différent - un Multimap permet l'association de plusieurs valeurs à une seule clé. Le résultat de l'exécution du code ci-dessus est le suivant:

Answer=42
Hello=Mom
Hello=World

Comme on peut le voir, pour le "Hello" clé, les valeurs de "Mom" et "World" associé avec. Contrairement à Hashtable, il n'écarte pas l'une des valeurs et ne la remplace pas par une autre. Multimap est capable de conserver plusieurs valeurs pour chaque clé.

8
coobird

Plutôt que de donner une autre réponse multipmap, je vous demanderai pourquoi vous voulez faire cela?

Les multiples valeurs sont-elles liées? Si oui, il est probablement préférable de créer une structure de données pour les contenir. Si non, il est peut-être plus approprié d'utiliser des cartes distinctes.

Les gardez-vous ensemble pour pouvoir les répéter en fonction de la clé? Vous souhaiterez peut-être rechercher une autre structure de données d'indexation, comme une SkipList.

7
kdgregory

Comme d'autres l'ont souligné, non. Au lieu de cela, envisagez d'utiliser un Multimap qui peut mapper plusieurs valeurs pour la même clé.

Le Google Collections ( update: Guava ) La bibliothèque contient une implémentation, et est probablement votre meilleur choix.

Modifier : bien sûr, vous pouvez faire comme Eric suggère , et stocker une collection en tant que valeur dans votre table de hachage (ou carte, plus généralement), mais cela signifie écrire vous-même du code passe-partout inutile. Lorsque vous utilisez une bibliothèque comme Google Collections, elle s'occupe de la "plomberie" de bas niveau pour vous. Découvrez ceci bel exemple de la façon dont votre code serait simplifié en utilisant Multimap au lieu de Vanilla Java classes Collections.

5
Jonik

Aucune des réponses n'a indiqué ce que je ferais d'abord.

Le plus grand saut que j'ai jamais fait dans mes capacités OO était quand j'ai décidé de TOUJOURS faire un autre cours quand il semblait que cela pourrait même être légèrement utile - et c'est l'une des choses que j'ai appris de suivre ce modèle.

Presque tout le temps, je trouve qu'il existe une relation entre les objets que j'essaie de placer dans une table de hachage. Plus souvent qu'autrement, il y a de la place pour une classe - même une méthode ou deux.

En fait, je trouve souvent que je ne veux même pas d'une structure de type HashMap - un simple HashSet fait l'affaire.

L'élément que vous stockez en tant que clé primaire peut devenir l'identité d'un nouvel objet - vous pouvez donc créer des méthodes égales et de hachage qui ne font référence qu'à cet objet (Eclipse peut créer vos égales et vos méthodes de hachage pour vous facilement). De cette façon, le nouvel objet enregistrera, triera et récupérera exactement comme votre objet d'origine, puis utilisera les propriétés pour stocker le reste des éléments.

La plupart du temps quand je fais ça, je trouve qu'il y a quelques méthodes qui y vont aussi et avant que je le sache, j'ai un objet à part entière qui aurait dû être là tout le temps mais je ne l'ai jamais reconnu, et un tas d'ordures facteurs de mon code.

Afin d'en faire une "étape bébé", je crée souvent la nouvelle classe contenue dans ma classe d'origine - parfois je contiens même la classe dans une méthode si cela a du sens de l'étendre de cette façon - puis je la déplace autour comme il devient plus clair que ce devrait être une classe de première classe.

4
Bill K

Faites le vôtre:

Map<Object, List<Object>> multiMap = new HashMap<Object, List<Object>>();

Ajouter:

  public void add(String key, Object o) {
    List<Object> list;
    if (multiMap.containsKey(key)) {
      list = multiMap.get(key);
      list.add(o);
    } else {
      list = new ArrayList<Object>();
      list.add(o);
      multiMap.put(key, list);
    }
  }
4
Cambium

Voir Google Collections Library pour les multimaps et autres collections similaires. Les collections intégrées n'ont pas de support direct pour cela.

2
Carl Manaster

Ce que vous recherchez est un Multimap . goi collections api fournit une implémentation de Nice et bien d'autres choses qui méritent d'être apprises à utiliser. Hautement recommandé!

2
bendin

Vous devez utiliser quelque chose appelé MultiMap . Ce n'est pas strictement une carte cependant, c'est une API différente. C'est à peu près la même chose que Map <K, List <V>>, mais vous n'aurez pas de méthodes comme entrySet () ou values ​​().

1
Mark Renouf

Facile. Au lieu de Hashtable<Key, Value>, utilisation Hashtable<Key, Vector<Value>>.

1
luiscubal

Code suivant sans la bibliothèque Guava de Google. Il est utilisé pour la valeur double comme clé et ordre trié

Map<Double,List<Object>> multiMap = new TreeMap<Double,List<Object>>();

for( int i= 0;i<15;i++)
{
    List<Object> myClassList = multiMap.get((double)i);
    if(myClassList == null)
    {
        myClassList = new ArrayList<Object>();
        multiMap.put((double) i,myClassList);
    }
    myClassList.add("Value "+ i);
}

List<Object> myClassList = multiMap.get((double)0);
if(myClassList == null)
{
    myClassList = new ArrayList<Object>();
    multiMap.put( (double) 0,myClassList);
}
myClassList.add("Value Duplicate");
for (Map.Entry entry : multiMap.entrySet()) 
{
  System.out.println("Key = " + entry.getKey() + ", Value = " +entry.getValue());
}
0
Somnath Kadam

Outre les collections Google, il existe un objet Apache Commons Collection pour MultiMap

0
sheki