Java Hashmap: Comment obtenir la clé de la valeur?

Si j’ai la valeur "foo" , et un HashMap ftw pour lequel ftw.containsValue("foo") renvoie true , comment puis-je obtenir la clé correspondante? Dois-je parcourir le hashmap? Quelle est la meilleure façon de le faire?

Si vous choisissez d’utiliser la bibliothèque Commons Collections au lieu de l’API Java Collections standard, vous pouvez y parvenir facilement.

L’interface BidiMap de la bibliothèque Collections est une carte bidirectionnelle qui vous permet de mapper une clé sur une valeur (comme les cartes normales) et de mapper une valeur sur une clé, ce qui vous permet d’effectuer des recherches dans les deux sens. L’obtention d’une clé pour une valeur est prise en charge par la méthode getKey () .

Cependant, les mappages bidi ne peuvent pas avoir plusieurs valeurs mappées à des clés. Par conséquent, à moins que votre fichier ne comporte des correspondances 1: 1 entre les clés et les valeurs, vous ne pouvez pas utiliser les bidimaps.

Mettre à jour

Si vous souhaitez utiliser l’API Java Collections, vous devez vous assurer de la relation 1: 1 entre les clés et les valeurs au moment de l’insertion de la valeur dans la carte. C’est plus facile à dire qu’à faire.

Une fois que vous pouvez vous en assurer, utilisez la méthode entrySet () pour obtenir l’ensemble des entrées (mappages) dans la carte. Une fois que vous avez obtenu l’ensemble dont le type est Map.Entry , parcourez les entrées en comparant la valeur stockée à la valeur attendue et obtenez la clé correspondante .

Mise à jour n ° 2

La prise en charge des cartes bidirectionnelles avec des génériques se trouve dans Google Guava et dans les bibliothèques Commons-Collections refactorisées (cette dernière n’est pas un projet Apache). Merci à Esko d’avoir souligné le support générique manquant dans Apache Commons Collections. Utiliser des collections avec des génériques rend le code plus maintenable.

Si votre structure de données comporte un mappage plusieurs à un entre les clés et les valeurs, vous devez effectuer une itération sur les entrées et sélectionner toutes les clés appropriées:

 public static  Set getKeysByValue(Map map, E value) { Set keys = new HashSet(); for (Entry entry : map.entrySet()) { if (Objects.equals(value, entry.getValue())) { keys.add(entry.getKey()); } } return keys; } 

En cas de relation un-à-un , vous pouvez renvoyer la première clé correspondante:

 public static  T getKeyByValue(Map map, E value) { for (Entry entry : map.entrySet()) { if (Objects.equals(value, entry.getValue())) { return entry.getKey(); } } return null; } 

Dans Java 8:

 public static  Set getKeysByValue(Map map, E value) { return map.entrySet() .stream() .filter(entry -> Objects.equals(entry.getValue(), value)) .map(Map.Entry::getKey) .collect(Collectors.toSet()); } 

De plus, pour les utilisateurs de goyave, BiMap peut être utile. Par exemple:

 BiMap tokenToChar = ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '('); Token token = tokenToChar.inverse().get('('); Character c = tokenToChar.get(token); 
 public class NewClass1 { public static void main(Ssortingng[] args) { Map testMap = new HashMap(); testMap.put(10, "a"); testMap.put(20, "b"); testMap.put(30, "c"); testMap.put(40, "d"); for (Entry entry : testMap.entrySet()) { if (entry.getValue().equals("c")) { System.out.println(entry.getKey()); } } } } 

Quelques infos supplémentaires … Peut vous être utile

La méthode ci-dessus peut ne pas être bonne si votre hashmap est vraiment grand. Si votre hashmap contient une clé unique pour un mappage de valeur unique, vous pouvez gérer un hashmap supplémentaire contenant un mappage de valeur à clé.

C’est vous devez maintenir deux hashmaps

 1. Key to value 2. Value to key 

Dans ce cas, vous pouvez utiliser le second hashmap pour obtenir la clé.

Vous pouvez insérer la clé, la paire de valeurs et son inverse dans la structure de votre carte

 map.put("theKey", "theValue"); map.put("theValue", "theKey"); 

Utiliser map.get (“theValue”) renverra alors “theKey”.

C’est un moyen rapide et sale de faire des cartes constantes, qui ne fonctionnent que pour quelques ensembles de données sélectionnés:

  • Contient seulement 1 à 1 paires
  • L’ensemble des valeurs est disjoint du jeu de clés (1-> 2, 2-> 3 le rompt)

Je pense que vos choix sont

  • Utilisez une implémentation de carte conçue pour cela, comme le BiMap des collections Google. Notez que les collections Google BiMap nécessitent des valeurs uniques, ainsi que des clés, mais elles offrent des performances élevées dans les deux sens.
  • Maintenir manuellement deux cartes – une pour la clé -> valeur, et une autre carte pour la valeur -> clé
  • entrySet() le entrySet() et trouvez les clés correspondant à la valeur. C’est la méthode la plus lente, car elle nécessite une itération dans toute la collection, alors que les deux autres méthodes ne le nécessitent pas.

Pour trouver toutes les clés correspondant à cette valeur, parcourez toutes les paires dans le hashmap, à l’aide de map.entrySet() .

Il n’y a pas de réponse claire, car plusieurs clés peuvent correspondre à la même valeur. Si vous appliquez l’unicité avec votre propre code, la meilleure solution consiste à créer une classe qui utilise deux Hashmaps pour suivre les mappages dans les deux directions.

Décorez la carte avec votre propre implémentation

 class MyMap extends HashMap{ Map reverseMap = new HashMap(); @Override public V put(K key, V value) { // TODO Auto-generated method stub reverseMap.put(value, key); return super.put(key, value); } public K getKey(V value){ return reverseMap.get(value); } } 

Je pense que c’est la meilleure solution, adresse originale: Java2s

  import java.util.HashMap; import java.util.Map; public class Main { public static void main(Ssortingng[] argv) { Map map = new HashMap(); map.put("1","one"); map.put("2","two"); map.put("3","three"); map.put("4","four"); System.out.println(getKeyFromValue(map,"three")); } // hm is the map you are trying to get value from it public static Object getKeyFromValue(Map hm, Object value) { for (Object o : hm.keySet()) { if (hm.get(o).equals(value)) { return o; } } return null; } } 

Une utilisation simple: si vous mettez toutes les données dans hasMap et que vous avez item = “Automobile”, vous regardez sa clé dans hashMap. c’est une bonne solution.

 getKeyFromValue(hashMap, item); System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item)); 

Si vous créez la carte dans votre propre code, essayez de mettre la clé et la valeur dans la carte ensemble:

 public class KeyValue { public Object key; public Object value; public KeyValue(Object key, Object value) { ... } } map.put(key, new KeyValue(key, value)); 

Ensuite, lorsque vous avez une valeur, vous avez également la clé.

Je crains que vous deviez simplement parcourir votre carte. Le plus court je pourrais venir avec:

 Iterator> iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); if (entry.getValue().equals(value_you_look_for)) { Ssortingng key_you_look_for = entry.getKey(); } } 

Il semble que le meilleur moyen soit de parcourir les entrées à l’aide de map.entrySet() car map.containsValue() probablement de toute façon.

 for(int key: hm.keySet()) { if(hm.get(key).equals(value)) { System.out.println(key); } } 

En utilisant Java 8:

 ftw.forEach((key, value) -> { if (value=="foo") { System.out.print(key); } }); 

Pour les API de ciblage de développement Android <19, la solution de relations personnelles de Vitalii Fedorenko ne fonctionne pas car Objects.equals n’est pas implémenté. Voici une solution simple:

 public  K getKeyByValue(Map map, V value) { for (Map.Entry entry : map.entrySet()) { if (value.equals(entry.getValue())) { return entry.getKey(); } } return null; } 

Vous pouvez utiliser le ci-dessous:

 public class HashmapKeyExist { public static void main(Ssortingng[] args) { HashMap hmap = new HashMap(); hmap.put("1", "Bala"); hmap.put("2", "Test"); Boolean cantain = hmap.containsValue("Bala"); if(hmap.containsKey("2") && hmap.containsValue("Test")) { System.out.println("Yes"); } if(cantain == true) { System.out.println("Yes"); } Set setkeys = hmap.keySet(); Iterator it = setkeys.iterator(); while(it.hasNext()) { Ssortingng key = (Ssortingng) it.next(); if (hmap.get(key).equals("Bala")) { System.out.println(key); } } } } 

Vous pouvez obtenir la clé en utilisant les valeurs en utilisant le code suivant.

 ArrayList valuesList = new ArrayList(); Set keySet = initalMap.keySet(); ArrayList keyList = new ArrayList(keySet); for(int i = 0 ; i < keyList.size() ; i++ ) { valuesList.add(initalMap.get(keyList.get(i))); } Collections.sort(valuesList); Map finalMap = new TreeMap(); for(int i = 0 ; i < valuesList.size() ; i++ ) { String value = (String) valuesList.get(i); for( int j = 0 ; j < keyList.size() ; j++ ) { if(initalMap.get(keyList.get(j)).equals(value)) { finalMap.put(keyList.get(j),value); } } } System.out.println("fianl map ----------------------> " + finalMap); 
 public static class SmartHashMap  { public HashMap keyValue; public HashMap valueKey; public SmartHashMap(){ this.keyValue = new HashMap(); this.valueKey = new HashMap(); } public void add(T1 key, T2 value){ this.keyValue.put(key, value); this.valueKey.put(value, key); } public T2 getValue(T1 key){ return this.keyValue.get(key); } public T1 getKey(T2 value){ return this.valueKey.get(value); } } 
 public static Ssortingng getKey(Map mapref, Ssortingng value) { Ssortingng key = ""; for (Map.Entry map : mapref.entrySet()) { if (map.getValue().toSsortingng().equals(value)) { key = map.getKey(); } } return key; } 

Oui, vous devez parcourir le hashmap, sauf si vous implémentez quelque chose comme ce que suggèrent ces différentes réponses. Plutôt que de manipuler le entrySet, je récupérerais simplement le keySet (), itérerais cet ensemble et conserverais la (première) clé qui vous fournira votre valeur correspondante. Si vous avez besoin de toutes les clés correspondant à cette valeur, vous devez évidemment tout faire.

Comme Jonas le suggère, c’est peut-être déjà ce que fait la méthode containsValue, vous pouvez donc simplement ignorer ce test et faire l’itération à chaque fois (ou peut-être que le compilateur éliminera déjà la redondance, qui sait).

Par rapport aux autres réponses, si votre carte inversée ressemble à

 Map> 

vous pouvez traiter des mappages de clés non-uniques, si vous avez besoin de cette fonctionnalité (les démêler de côté). Cela incorporerait bien dans toutes les solutions que les gens suggèrent ici en utilisant deux cartes.

 import java.util.HashMap; import java.util.HashSet; import java.util.Set; public class ValueKeysMap extends HashMap { HashMap> ValueKeysMap = new HashMap>(); @Override public boolean containsValue(Object value) { return ValueKeysMap.containsKey(value); } @Override public V put(K key, V value) { if (containsValue(value)) { Set keys = ValueKeysMap.get(value); keys.add(key); } else { Set keys = new HashSet(); keys.add(key); ValueKeysMap.put(value, keys); } return super.put(key, value); } @Override public V remove(Object key) { V value = super.remove(key); Set keys = ValueKeysMap.get(value); keys.remove(key); if(keys.size() == 0) { ValueKeysMap.remove(value); } return value; } public Set getKeys4ThisValue(V value){ Set keys = ValueKeysMap.get(value); return keys; } public boolean valueContainsThisKey(K key, V value){ if (containsValue(value)) { Set keys = ValueKeysMap.get(value); return keys.contains(key); } return false; } /* * Take care of argument constructor and other api's like putAll */ } 
 /** * This method gets the Key for the given Value * @param paramName * @return */ private Ssortingng getKeyForValueFromMap(Ssortingng paramName) { Ssortingng keyForValue = null; if(paramName!=null)) { Set> entrySet = myMap().entrySet(); if(entrySet!=null && entrySet.size>0) { for(Entry entry : entrySet) { if(entry!=null && paramName.equalsIgnoreCase(entry.getValue())) { keyForValue = entry.getKey(); } } } } return keyForValue; } 
 import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Set; public class M{ public static void main(Ssortingng[] args) { HashMap> resultHashMap = new HashMap>(); Set newKeyList = resultHashMap.keySet(); for (Iterator iterator = originalHashMap.keySet().iterator(); iterator.hasNext();) { Ssortingng hashKey = (Ssortingng) iterator.next(); if (!newKeyList.contains(originalHashMap.get(hashKey))) { List loArrayList = new ArrayList(); loArrayList.add(hashKey); resultHashMap.put(originalHashMap.get(hashKey), loArrayList); } else { List loArrayList = resultHashMap.get(originalHashMap .get(hashKey)); loArrayList.add(hashKey); resultHashMap.put(originalHashMap.get(hashKey), loArrayList); } } System.out.println("Original HashMap : " + originalHashMap); System.out.println("Result HashMap : " + resultHashMap); } } 

Utilisez un wrapper fin: HMap

 import java.util.Collections; import java.util.HashMap; import java.util.Map; public class HMap { private final Map> map; public HMap() { map = new HashMap>(); } public HMap(final int initialCapacity) { map = new HashMap>(initialCapacity); } public boolean containsKey(final Object key) { return map.containsKey(key); } public V get(final Object key) { final Map entry = map.get(key); if (entry != null) return entry.values().iterator().next(); return null; } public K getKey(final Object key) { final Map entry = map.get(key); if (entry != null) return entry.keySet().iterator().next(); return null; } public V put(final K key, final V value) { final Map entry = map .put(key, Collections.singletonMap(key, value)); if (entry != null) return entry.values().iterator().next(); return null; } } 

Mes 2 centimes Vous pouvez obtenir les clés dans un tableau, puis parcourir le tableau. Cela affectera les performances de ce bloc de code si la carte est assez grande, où vous obtenez d’abord les clés dans un tableau pouvant consumr un certain temps, puis vous bouclez. Sinon, pour les cartes plus petites, ça devrait aller.

 Ssortingng[] keys = yourMap.keySet().toArray(new Ssortingng[0]); for(int i = 0 ; i < keys.length ; i++){ //This is your key String key = keys[i]; //This is your value yourMap.get(key) } 

Bien que cela ne réponde pas directement à la question, elle est liée.

De cette façon, vous n’avez pas besoin de continuer à créer / itérer. Créez simplement une carte inversée une fois et obtenez ce dont vous avez besoin.

 /** * Both key and value types must define equals() and hashCode() for this to work. * This takes into account that all keys are unique but all values may not be. * * @param map * @param  * @param  * @return */ public static  Map> reverseMap(Map map) { if(map == null) return null; Map> reverseMap = new ArrayMap<>(); for(Map.Entry entry : map.entrySet()) { appendValueToMapList(reverseMap, entry.getValue(), entry.getKey()); } return reverseMap; } /** * Takes into account that the list may already have values. * * @param map * @param key * @param value * @param  * @param  * @return */ public static  Map> appendValueToMapList(Map> map, K key, V value) { if(map == null || key == null || value == null) return map; List list = map.get(key); if(list == null) { List newList = new ArrayList<>(); newList.add(value); map.put(key, newList); } else { list.add(value); } return map; } 

En java8

 map.entrySet().stream().filter(entry -> entry.getValue().equals(value)) .forEach(entry -> System.out.println(entry.getKey())); 

Il est important de noter que depuis cette question, Apache Collections prend en charge les BidiMaps génériques . Ainsi, quelques-unes des réponses les mieux votées ne sont plus exactes sur ce point.

Pour un BidiMap sérialisé qui prend également en charge les valeurs en double (scénario 1 vers plusieurs), considérez également MapDB.org .

  1. Si vous voulez obtenir la clé de la valeur, il est préférable d’utiliser bidimap (cartes bidirectionnelles), vous pouvez obtenir la clé de la valeur dans le temps O (1).

    Mais l’inconvénient est que vous ne pouvez utiliser qu’un jeu de clés et un jeu de valeurs uniques.

  2. Il y a une structure de données appelée Table en Java, qui n’est rien d’autre qu’une carte de cartes comme

    Tableau == carte >

    Ici, vous pouvez obtenir la map en interrogeant T.row(a); , et vous pouvez également obtenir la map en interrogeant T.column(b);

Dans votre cas particulier, insérez C comme une constante.

Donc, il a comme , …

Donc, si vous trouvez via T.row (a1) —> retourne la carte de -> get keyset cette carte retournée.

Si vous avez besoin de trouver la valeur de la clé, T.column (b2) -> renvoie map of -> get keyset de la map retournée.

Avantages par rapport au cas précédent:

  1. Peut utiliser plusieurs valeurs.
  2. Plus efficace lorsque vous utilisez des ensembles de données volumineux.

Je pense que keySet () peut être utile pour trouver les clés correspondant à la valeur et avoir un meilleur style de codage que entrySet () .

Ex:

Supposons que vous ayez une carte HashMap, ArrayList res , une valeur à laquelle vous voulez trouver tous les mappages de clés , puis stockez les clés dans la res .

Vous pouvez écrire le code ci-dessous:

  for (int key : map.keySet()) { if (map.get(key) == value) { res.add(key); } } 

plutôt que d’utiliser entrySet () ci-dessous:

  for (Map.Entry s : map.entrySet()) { if ((int)s.getValue() == value) { res.add((int)s.getKey()); } } 

J’espère que cela aide 🙂