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


450

Si j'ai la valeur "foo"et a HashMap<String> ftwpour laquelle ftw.containsValue("foo")retourne true, comment puis-je obtenir la clé correspondante? Dois-je parcourir le hashmap? Quelle est la meilleure façon de le faire?


72
Notez qu'il n'y a pas de clé correspondante unique - il peut très bien y avoir plusieurs clés mappées à la même valeur.
CPerkins

1
@CPerkins mais pour les hashmaps comme <strFilename, Reader> et bien d'autres 1 à 1, c'est très utile.
Aquarius Power

si vous avez une petite collection d'articles, pensez à créer des constantes public static final String TIME = "time";etproperties.put(TIME, PbActivityJpa_.time);
Basheer AL-MOMANI

cela pourrait probablement vous aider à obtenir les données de la carte et vous pouvez également effectuer une sorte de traitement. frugalisminds.com/java/java-8-stream-map-examples
Sanjay-Dev

Réponses:


215

Si vous choisissez d'utiliser la bibliothèque Commons Collections au lieu de l'API Java Collections standard, vous pouvez le faire facilement.

L' interface BidiMap de la bibliothèque Collections est une carte bidirectionnelle, vous permettant de mapper une clé à une valeur (comme les cartes normales), ainsi que 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 prise en charge par la méthode getKey () .

Il y a cependant une mise en garde, les cartes bidi ne peuvent pas avoir plusieurs valeurs 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 de bidimaps.

Mise à jour

Si vous souhaitez vous fier à l'API Java Collections, vous devrez garantir 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, comparez la valeur stockée à celle attendue et obtenez la clé correspondante .

Mise à jour # 2

La prise en charge des cartes bidi avec des génériques peut être trouvée dans Google Guava et dans les bibliothèques Commons-Collections remaniées (cette dernière n'est pas un projet Apache). Merci à Esko d'avoir souligné le support générique manquant dans les collections Apache Commons. L'utilisation de collections avec des génériques rend le code plus facile à gérer.


23
... et si vous aimez les génériques et tout ce qui est moderne, Google Collections dispose de BiMap où vous pouvez obtenir la clé correspondant à la valeur spécifiée en appelant biMap.inverse (). get (value);
Esko

1
Oui, Apache Commons Collections ne prend pas en charge les génériques. Cependant, il y a Google Collections comme vous l'avez souligné (que je n'utilise pas encore - pas encore de version 1.0), et il y a les Commons-Collections refactorisées avec le support des génériques. Vous le trouverez en tant que projet Sourceforge @ sourceforge.net/projects/collections
Vineet Reynolds

2
Les collections Google ne sont pas une version remaniée de Commons-Collections.
whiskeysierra

12
@whiskeysierra: Je pense que personne ne le dit (actuellement).
Huff

2
Collections Apache supporte désormais génériques commons.apache.org/proper/commons-collections/javadocs/...~~V~~plural~~3rd
Kervin

603

Si votre structure de données a un mappage plusieurs à un entre les clés et les valeurs, vous devez parcourir les entrées et sélectionner 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 d' un à une relation, vous pouvez retourner la première clé adapté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());
}

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

BiMap<Token, Character> tokenToChar = 
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);

3
Pouvez-vous nous parler de la performance? Quoi de plus optimisé? Ceci ou BidiMap?
tasomaniac

J'ai pensé la même solution, je l'ai bien sûr votée mais je doute de son efficacité quand il s'agit de très grandes Collections.
arjacsoh

3
stackoverflow.com/questions/4553624/hashmap-get-put-complexity HashMap a une complexité temporelle o(1). Si vous parcourez les valeurs, cela tuera les performances. Si vous voulez une relation et que vous avez better performanceune one-onerelation, vous pouvez utiliser another mapvalue is a key
veer7

3
Je recommande de remplacer .filter(entry -> entry.getValue().equals(value))par car aucune déclaration sur la capacité n'a été faite. De plus, vous pouvez remplacer par.filter(entry ->Objects.equals(entry.getValue(), value))null.map(entry -> entry.getKey()).map(Map.Entry::getKey)
Holger

j'ai du mal à comprendre la notation <T, E> avant Set <T> getKeysByValue () ... à quoi ça sert ... une manière différente de le faire sans utiliser ça? merci
ponderingdev

76
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

La méthode ci-dessus peut ne pas être bonne si votre hashmap est vraiment grand. Si votre table de hachage contient une clé unique vers un mappage de valeur unique, vous pouvez conserver une autre carte de hachage contenant le mappage de la valeur à la clé.

C'est-à-dire que vous devez conserver deux hashmaps

1. Key to value

2. Value to key 

Dans ce cas, vous pouvez utiliser la deuxième table de hachage pour obtenir la clé.


19

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.
  • Gérez manuellement deux cartes - une pour clé -> valeur et une autre pour valeur -> clé
  • Parcourez entrySet()et pour trouver les clés qui correspondent à la valeur. Il s'agit de la méthode la plus lente, car elle nécessite une itération dans toute la collection, tandis que les deux autres méthodes ne nécessitent pas cela.

19

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

L'utilisation de map.get ("theValue") renverra alors "theKey".

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

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

4
Ce n'est pas vraiment correct. Cela ne nécessite pas seulement 1-1, mais aussi que l'ensemble de valeurs soit disjoint de l'ensemble de clés. Vous ne pouvez pas appliquer cela à la carte bijective {1 -> 2, 2 -> 3}: 2 est à la fois une valeur et une clé.
Luis A. Florit

15

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

Je pense que c'est une approche intéressante, mais comme la relation doit être de 1: 1, je me débarrasserais complètement de HashMap et mettrais en œuvre l'interface Map <K, V> à la place afin d'éviter les doublons des valeurs et des clés.
Fran Marzoa

11

Il n'y a pas de réponse sans ambiguïté, 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.


11

Pour trouver toutes les clés qui correspondent à cette valeur, parcourez toutes les paires de la table de hachage, en utilisant map.entrySet().


4
Cette solution est horriblement intensive, au point qu'elle n'est pas pratique sur les grands HashMaps.
Joehot200

10

Utilisation de Java 8:

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

6
value=="foo" cela ne fonctionnera pas. equalsdoit être utilisé pour comparer les chaînes.
Anton Balaniuc

@Anton, vrai, sauf s'il valuea été interné.
frododot

9

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

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é.


3
Intelligent, mais que se passe-t-il s'il y a 2 ou plusieurs objets KeyValue contenant la même valeur? Quelle clé choisir?
Vineet Reynolds

2
@Vineet, je ne vois pas comment cette approche résout la question du PO. qu'avez-vous voulu dire par "Alors quand vous avez une valeur, vous avez aussi la clé."?
Qiang Li

9

Je pense que c'est la meilleure solution, adresse d'origine: 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 recherchez donc sa clé dans hashMap. c'est une bonne solution.

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

7

Je crains que vous n'ayez qu'à répéter 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
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}

6

Il semble que la meilleure façon est d'itérer sur les entrées en utilisant map.entrySet()car map.containsValue()cela fait probablement de toute façon.


Oui, c'est exactement ce que ça fait. Mais bien sûr, il retourne vrai dès qu'il trouve une valeur pour laquelle .equals est vrai, par opposition à ce que OP devra probablement faire.
CPerkins

1
Eh bien, l'itération sur les entrées peut retourner avec la clé dès qu'elle trouve également une valeur correspondante. Les correspondances multiples ne semblent pas être un problème.
Jonas K

6

Pour le développement Android ciblant l'API <19, la solution de relation univoque Vitalii Fedorenko ne fonctionne pas car elle Objects.equalsn'est pas implémentée. 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;
}

Cette solution fonctionne pour moi; également en développement pour une version Android archéologique, dans mon cas pour obtenir la clé d'un marqueur Google Map tenu dans une carte dans un événement "onMarkerClick". Itération des travaux entrySet; mais itérer les clés et les faire correspondre aux entrées avec get (), et comparer la sortie, ne l'a pas fait.
Toby Wilson

3

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

C'est bien que vous souhaitiez fournir des informations utiles, mais cela ne devrait pas être une réponse "code uniquement" et le code lui-même ne devrait pas non plus être plein d'odeurs de code.
Tom

2

Oui, vous devez parcourir le hashmap, sauf si vous implémentez quelque chose dans le sens de ce que suggèrent ces différentes réponses. Plutôt que de jouer avec le entrySet, j'obtiendrais simplement le keySet (), itérerais sur cet ensemble et garderais la (première) clé qui vous obtiendrait votre valeur correspondante. Si vous avez besoin de toutes les clés correspondant à cette valeur, vous devez évidemment tout faire.

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

En outre, par rapport aux autres réponses, si votre carte inversée ressemble

Map<Value, Set<Key>>

vous pouvez gérer des mappages de valeurs>> clés non uniques, si vous avez besoin de cette capacité (les démêler de côté). Cela s'intégrerait parfaitement à l'une des solutions suggérées ici à l'aide de deux cartes.


2

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

}

Je pense que cette réponse pourrait être améliorée en ajoutant une explication.
Jonathan

2
-1. Je l'ai testé avec Stringcomme clé et valeur. Lorsque j'appelle, map.add("1", "2"); map.add("1","3");je peux appeler map.getKey("2");et récupérer "1", même si "1"c'est la clé pour "3".
jlordo

@Jonathan l'idée derrière cette classe est de conserver un autre HashMap avec les mappages inversés afin qu'en plus de récupérer une valeur d'une clé, vous pouvez récupérer une clé d'une valeur. Les classes T1 et T2 sont un peu déroutantes; peut-être les nommer littéralement Key & Value à la place? Bien que je m'attendrais à pouvoir recevoir plus d'une valeur ou plus d'une clé en retour, selon les données et ce que vous voulez. À utiliser avec prudence
Chicowitz

1
@theknightwhosaysni "1" n'est plus la clé de "2" (plus). C'est aussi la réponse à votre question, l'appel getValue("1")reviendra 3.
jlordo

Désolé jlordo, je me suis trompé sur le comportement Hashmap standard: vous avez raison en ce que l'ajout d'une nouvelle valeur pour une clé devrait remplacer l'ancienne valeur
Chicowitz

2

Dans java8

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

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

Map <String, Integer> map = new HashMap <String, Integer> (); map.put ("A", 1); map.put ("B", 2); map.put ("C", 3); map.put ("D", 4); // System.out.println (carte); System.out.println (getKey (map, "4"));
Amazing India

1
Que se passe-t-il si plusieurs clés ont la même valeur?
Cà phê đen

Lorsque vous passez les clés multiples ont la même valeur, nous obtiendrons la dernière clé comme résultat. exemple: sortie A 1, B 1, C 1, D 2: si nous passons la valeur 1, la sortie sera C
Amazing India

@AmazingIndia Ceci n'est pas garanti et dépend complètement de l'implémentation de la carte spécifique. HashMap par exemple ne garantit pas une commande, vous n'avez donc aucune idée de la sortie qui sera retournée ici.
Niels Doucet

1
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
/**
 * 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
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

Utilisez un emballage mince: 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

Mes 2 cents. 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, ce qui pourrait prendre un certain temps, puis vous bouclez. Sinon, pour les petites cartes, cela devrait être correct.

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

Et pourquoi quelqu'un devrait-il utiliser cette approche? Comme vous l'avez déjà dit, les performances seraient pires que dans d'autres approches.
Tom

1

Je pense que keySet () peut être bien pour trouver les clés mappant à 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 souhaitez trouver tout le mappage de clés , puis stockez les clés dans la res .

Vous pouvez écrire du 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 :)


map.get(key) == valuen'est pas une bonne idée lors de la vérification de l'égalité des objets, car vous comparez des références. L'égalité des objets doit toujours utiliser leur.equals()
frododot

1

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

0

Il est important de noter que depuis cette question, Apache Collections prend en charge les BidiMaps génériques . Ainsi, certaines des réponses les plus 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 à plusieurs), pensez également à MapDB.org .


0
  1. Si vous souhaitez obtenir la clé de la valeur, il est préférable d'utiliser la bidimap (cartes bidirectionnelles), vous pouvez obtenir la clé de la valeur en 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 <A, B, C> == carte <A, carte <B, C>>

    Ici, vous pouvez obtenir map<B,C>en interrogeant T.row(a);, et vous pouvez également obtenir map<A,C>en interrogeantT.column(b);

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

Donc, comme <a1, b1, 1> <a2, b2, 1>, ...

Donc, si vous trouvez via T.row (a1) ---> retourne la carte de -> obtenez le jeu de clés de cette carte retournée.

Si vous avez besoin de trouver la valeur de clé, T.column (b2) -> renvoie la carte de -> récupère le jeu de clés 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.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.