Java Hashmap: comment obtenir la clé à partir de la valeur?

si j'ai la valeur "foo" , et un HashMap<String> ftw pour lequel ftw.containsValue("foo") retourne true , Comment puis-je obtenir la clé correspondante? Dois-je faire une boucle à travers le hashmap? Quelle est la meilleure façon de le faire?

380
demandé sur Nick Heiner 2009-09-05 21:07:00

30 réponses

si vous choisissez d'utiliser la Commons Collections library au lieu de L'API Java Collections standard, vous pouvez y parvenir facilement.

l'interface BidiMap dans la bibliothèque des Collections est une carte bidirectionnelle, vous permettant de mapper une clé à une valeur (comme des cartes normales), et aussi de mapper une valeur à une clé, vous permettant ainsi d'effectuer des recherches dans les deux directions. L'obtention d'une clé pour une valeur est soutenue par le méthode getKey () .

il y a une mise en garde cependant, bidi maps ne peut pas avoir des valeurs multiples mappées sur des clés, et donc à moins que votre ensemble de données ait des mappages 1:1 entre les clés et les valeurs, vous ne pouvez pas utiliser bidimaps.

mise à Jour

si vous voulez vous fier à L'API Java Collections, vous devez vous assurer de la relation 1:1 entre les clés et les valeurs au moment d'insérer la valeur dans le cartographie. C'est plus facile à dire qu'à faire.

une fois que vous pouvez vous assurer que, Utilisez la méthode entrySet () pour obtenir l'ensemble des entrées (mappings) dans la carte. Une fois que vous avez obtenu l'ensemble dont le type est carte.Entrée , itérer à travers les entrées, en comparant la valeur stockée contre les attendus, et obtenir la clé correspondante .

mise à Jour #2

Support pour les cartes bidi avec génériques peut être trouvé dans Google Guava et le refactored Commons-Collections bibliothèques (ce dernier n'est pas un projet Apache). Merci à Esko d'avoir souligné l'absence de support générique dans les Collections Apache Commons. L'utilisation de collections avec des génériques rend le code plus maintenable.

195
répondu Vineet Reynolds 2016-01-28 21:14:45

si votre structure de données a plusieurs à un correspondance entre les clés et les valeurs, vous devriez itérer au-dessus des entrées et choisir toutes les clés appropriées:

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

dans le cas de one-to-one relation, vous pouvez retourner la première clé appariée:

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

En Java 8:

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

aussi, pour les utilisateurs de goyave, BiMap peut être utile. Exemple:

BiMap<Token, Character> tokenToChar = 
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
559
répondu Vitalii Fedorenko 2018-07-25 04:40:58
public class NewClass1 {

    public static void main(String[] args) {
       Map<Integer, String> testMap = new HashMap<Integer, String>();
        testMap.put(10, "a");
        testMap.put(20, "b");
        testMap.put(30, "c");
        testMap.put(40, "d");
        for (Entry<Integer, String> entry : testMap.entrySet()) {
            if (entry.getValue().equals("c")) {
                System.out.println(entry.getKey());
            }
        }
    }
}

quelques informations supplémentaires... Peut vous être utile

méthode ci-dessus peut ne pas être bon si votre hashmap est vraiment grand. Si votre hashmap contient une clé unique à la cartographie de valeur unique, vous pouvez maintenir un hashmap de plus qui contient la cartographie de valeur à clé.

C'est-à-dire que vous devez maintenir deux hachmaps

1. Key to value

2. Value to key 

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

70
répondu Fathah Rehman P 2016-03-02 05:54:28

vous pouvez insérer à la fois la clé, la paire de valeur et son inverse dans votre structure de carte

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

utilisant la carte.get ("theValue") retournera alors"theKey".

c'est un moyen rapide et sale que j'ai fait des cartes constantes, qui ne fonctionneront que pour quelques ensembles de données sélectionnés:

  • contient seulement 1 à 1 paire
  • ensemble de valeurs est disjoint de l'ensemble des clés (1->2, 2->3 151990920"
19
répondu Chicowitz 2016-02-04 00:42:41

je pense que vos choix sont

  • utilisez une implémentation de carte construite pour cela, comme le BiMap des collections google. Notez que les collections google BiMap nécessite uniqueless de valeurs, ainsi que des clés, mais il fournit de hautes performances dans les deux sens de la performance
  • gérer manuellement deux cartes-une pour la clé - > valeur, et une autre pour la valeur - > clé
  • entrySet() et de trouver les clés qui correspondent à la valeur. C'est la méthode la plus lente, car elle nécessite d'itérer à travers toute la collection, alors que les deux autres méthodes ne nécessitent pas cela.
17
répondu Chi 2016-01-28 21:30:53

pour trouver toutes les clés qui correspondent à cette valeur, itérez toutes les paires dans le hashmap, en utilisant map.entrySet() .

11
répondu wsorenson 2016-10-04 12:23:02

il n'y a pas de réponse univoque, car plusieurs clés peuvent correspondre à la même valeur. Si vous appliquez unique-ness avec votre propre code, la meilleure solution est de créer une classe qui utilise deux Hashmaps pour suivre les correspondances dans les deux sens.

10
répondu recursive 2009-09-05 17:08:57

Décorez la carte avec votre propre implémentation

class MyMap<K,V> extends HashMap<K, V>{

    Map<V,K> reverseMap = new HashMap<V,K>();

    @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);
    }
}
10
répondu ABHI 2016-05-23 13:45:03

je pense que c'est la meilleure solution, l'adresse originale: Java2s

    import java.util.HashMap;
    import java.util.Map;

        public class Main {

          public static void main(String[] argv) {
            Map<String, String> map = new HashMap<String, String>();
            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 facile: si vous mettez toutes les données dans hasMap et que vous avez item = "Automobile", vous cherchez donc sa clé dans hashMap. c'est une bonne solution.

getKeyFromValue(hashMap, item);
System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item));
8
répondu boy 2015-08-22 06:21:55

si vous construisez 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));

alors quand vous avez une valeur, vous avez aussi la clé.

7
répondu David Tinker 2009-09-05 17:58:54

je crains que vous n'ayez juste à itérer votre carte. Le plus court que j'ai pu trouver:

Iterator<Map.Entry<String,String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
    Map.Entry<String,String> entry = iter.next();
    if (entry.getValue().equals(value_you_look_for)) {
        String key_you_look_for = entry.getKey();
    }
}
6
répondu André van Toly 2010-05-28 09:52:58
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}
6
répondu user309309 2015-08-05 12:35:07

il semble que le meilleur moyen est pour vous d'itérer sur les entrées en utilisant map.entrySet() depuis map.containsValue() fait probablement cela de toute façon.

6
répondu Jonas Klemming 2015-08-22 06:11:34

Utilisant Java 8:

ftw.forEach((key, value) -> {
    if (value=="foo") {
        System.out.print(key);
    }
});
5
répondu phani 2015-09-09 10:32:04

pour Développement Android ciblant API < 19, Vitalii Fedorenko solution de relation un-à-un ne fonctionne pas parce que Objects.equals n'est pas mis en œuvre. Voici une alternative simple:

public <K, V> K getKeyByValue(Map<K, V> map, V value) {
    for (Map.Entry<K, V> entry : map.entrySet()) {
            if (value.equals(entry.getValue())) {
            return entry.getKey();
        }
    }
    return null;
}
5
répondu The Berga 2016-04-14 14:14:31

vous pouvez utiliser ce qui suit:

public class HashmapKeyExist {
    public static void main(String[] args) {
        HashMap<String, String> hmap = new HashMap<String, String>();
        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())
        {
            String key = (String) it.next();
            if (hmap.get(key).equals("Bala"))
            {
                System.out.println(key);
            }
        }
    }
}
3
répondu Balasubramanian Ganapathi 2016-11-09 23:24:22

vous pouvez obtenir la clé en utilisant des 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);
2
répondu Amit 2011-10-12 14:26:58
public static class SmartHashMap <T1 extends Object, T2 extends Object> {
    public HashMap<T1, T2> keyValue;
    public HashMap<T2, T1> valueKey;

    public SmartHashMap(){
        this.keyValue = new HashMap<T1, T2>();
        this.valueKey = new HashMap<T2, T1>();
    }

    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);
    }

}
2
répondu margus 2012-12-12 20:24:54
public static String getKey(Map<String, Integer> mapref, String value) {
    String key = "";
    for (Map.Entry<String, Integer> map : mapref.entrySet()) {
        if (map.getValue().toString().equals(value)) {
            key = map.getKey();
        }
    }
    return key;
}
2
répondu Amazing India 2017-06-22 07:34:51

Oui, vous devez faire une boucle à travers le hashmap, à moins que vous ne mettiez en œuvre quelque chose dans le sens de ce que ces différentes réponses suggèrent. Plutôt que de jouer avec l'entrySet, j'obtiendrais simplement le keySet(), itérerais sur cet ensemble, et garderais la (première) clé qui vous donne votre valeur correspondante. Si vous avez besoin de toutes les clés qui correspondent à cette valeur, évidemment vous devez faire toute la chose.

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

aussi, par rapport aux autres réponses, si votre carte ressemble à

Map<Value, Set<Key>>

vous pouvez traiter avec non-unique clé->les correspondances de valeur, si vous avez besoin de cette capacité (les démêler de côté). Cela incorporerait fine dans n'importe laquelle des solutions que les gens suggèrent ici en utilisant deux cartes.

1
répondu Carl 2009-09-05 19:45:31
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class ValueKeysMap<K, V> extends HashMap <K,V>{
    HashMap<V, Set<K>> ValueKeysMap = new HashMap<V, Set<K>>();

    @Override
    public boolean containsValue(Object value) {
        return ValueKeysMap.containsKey(value);
    }

    @Override
    public V put(K key, V value) {
        if (containsValue(value)) {
            Set<K> keys = ValueKeysMap.get(value);
            keys.add(key);
        } else {
            Set<K> keys = new HashSet<K>();
            keys.add(key);
            ValueKeysMap.put(value, keys);
        }
        return super.put(key, value);
    }

    @Override
    public V remove(Object key) {
        V value = super.remove(key);
        Set<K> keys = ValueKeysMap.get(value);
        keys.remove(key);
        if(keys.size() == 0) {
           ValueKeysMap.remove(value);
        }
        return value;
    }

    public Set<K> getKeys4ThisValue(V value){
        Set<K> keys = ValueKeysMap.get(value);
        return keys;
    }

    public boolean valueContainsThisKey(K key, V value){
        if (containsValue(value)) {
            Set<K> keys = ValueKeysMap.get(value);
            return keys.contains(key);
        }
        return false;
    }

    /*
     * Take care of argument constructor and other api's like putAll
     */
}
1
répondu Kanagavelu Sugumar 2015-02-25 06:06:54
/**
 * This method gets the Key for the given Value
 * @param paramName
 * @return
 */
private String getKeyForValueFromMap(String paramName) {
    String keyForValue = null;
    if(paramName!=null)) {
        Set<Entry<String,String>> entrySet = myMap().entrySet();
        if(entrySet!=null && entrySet.size>0) {
            for(Entry<String,String> entry : entrySet) {
                if(entry!=null && paramName.equalsIgnoreCase(entry.getValue())) {
                    keyForValue = entry.getKey();
                }
            }
        }
    }
    return keyForValue;
}
1
répondu kanaparthikiran 2015-05-22 05:56:27
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(String[] args) {

        HashMap<String, List<String>> resultHashMap = new HashMap<String, List<String>>();

        Set<String> newKeyList = resultHashMap.keySet();


        for (Iterator<String> iterator = originalHashMap.keySet().iterator(); iterator.hasNext();) {
            String hashKey = (String) iterator.next();

            if (!newKeyList.contains(originalHashMap.get(hashKey))) {
                List<String> loArrayList = new ArrayList<String>();
                loArrayList.add(hashKey);
                resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
            } else {
                List<String> 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);
    }
}
1
répondu Madhav 2015-08-20 10:40:12

utiliser un emballage fin: HMap

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class HMap<K, V> {

   private final Map<K, Map<K, V>> map;

   public HMap() {
      map = new HashMap<K, Map<K, V>>();
   }

   public HMap(final int initialCapacity) {
      map = new HashMap<K, Map<K, V>>(initialCapacity);
   }

   public boolean containsKey(final Object key) {
      return map.containsKey(key);
   }

   public V get(final Object key) {
      final Map<K, V> entry = map.get(key);
      if (entry != null)
         return entry.values().iterator().next();
      return null;
   }

   public K getKey(final Object key) {
      final Map<K, V> 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<K, V> entry = map
            .put(key, Collections.singletonMap(key, value));
      if (entry != null)
         return entry.values().iterator().next();
      return null;
   }
}
1
répondu Jayen 2015-08-22 06:27:21

mes 2 cents. Vous pouvez obtenir les clés dans un tableau et ensuite une boucle sur le tableau. Cela affectera la performance de ce bloc de code si la carte est assez grande , où dans vous obtenez les clés dans un tableau d'abord qui pourrait prendre un certain temps et puis vous êtes en boucle. Sinon pour des cartes plus petites il devrait être ok.

String[] keys =  yourMap.keySet().toArray(new String[0]);

for(int i = 0 ; i < keys.length ; i++){
    //This is your key    
    String key = keys[i];

    //This is your value
    yourMap.get(key)            
}
1
répondu Manu Bhat 2016-07-05 13:20:35

bien que cela ne réponde pas directement à la question, c'est lié.

de Cette façon, vous n'avez pas besoin de continuer à créer/itération. Il suffit de créer une carte inverse une fois et obtenir 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 <K>
 * @param <V>
 * @return
 */
public static <K, V> Map<V, List<K>> reverseMap(Map<K,V> map) {
    if(map == null) return null;

    Map<V, List<K>> reverseMap = new ArrayMap<>();

    for(Map.Entry<K,V> 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 <K>
 * @param <V>
 * @return
 */
public static <K, V> Map<K, List<V>> appendValueToMapList(Map<K, List<V>> map, K key, V value) {
    if(map == null || key == null || value == null) return map;

    List<V> list = map.get(key);

    if(list == null) {
        List<V> newList = new ArrayList<>();
        newList.add(value);
        map.put(key, newList);
    }
    else {
        list.add(value);
    }

    return map;
}
1
répondu Markymark 2018-02-01 23:22:05

Dans java8

map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
    .forEach(entry -> System.out.println(entry.getKey()));
0
répondu user3724331 2014-06-10 01:53:11

il est important de noter que depuis cette question, Apache Collections supporte Bidimaps Générique . Ainsi, quelques-unes des meilleures réponses votées ne sont plus exactes sur ce point.

pour une image bidimensionnelle sérialisée qui supporte aussi les valeurs dupliquées (scénario de 1 à plusieurs), considérez aussi MapDB.org .

0
répondu kervin 2015-05-31 16:25:49
  1. si vous voulez obtenir la clé de value, son meilleur pour utiliser bidimap (bi-directional maps) , vous pouvez obtenir la clé de value en O(1) Temps.

    mais, l'inconvénient avec ceci est que vous ne pouvez utiliser que des clés et des valeurs uniques.

  2. il existe une structure de données appelée Table en java, qui n'est rien d'autre qu'une carte de cartes comme

    Table < A, B, C > == carte < a, carte < B, C > >

    ici vous pouvez obtenir map<B,C> en demandant T.row(a); , et vous pouvez aussi obtenir map<A,C> en demandant T.column(b);

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

ainsi, il comme < a1, b1, 1 > < a2 , b2, 1 >,...

Donc, si vous trouvez via T. ligne(a1) ---> retourne la carte de --> obtenir keyset cette retourné la carte.

si vous avez besoin de trouver une valeur clé, alors, T. colonne(b2) --> retourne la carte de --> récupérez la clé de la carte retournée.

avantages par rapport au cas précédent:

  1. Peut utiliser plusieurs valeurs.
  2. Plus efficace lors de l'utilisation de grands ensembles de données.
0
répondu Batman 2016-11-07 15:06:25

je pense keySet() peut-être bien de trouver les clés de la cartographie de la valeur, et d'avoir un meilleur style de codage que entrySet() .

Ex:

supposez que vous avez un HashMap carte , ArrayList res , un valeur vous voulez trouver toute la clé mapping to, puis stocker les clés de 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());
        }
    }

Espère que cela aide :)

0
répondu FrancisGeek 2017-11-08 13:55:04