Java Hashmap: ¿Cómo obtener la clave del valor?

450

Si tengo el valor "foo"y un valor HashMap<String> ftwpara el que se ftw.containsValue("foo")devuelve true, ¿cómo puedo obtener la clave correspondiente? ¿Tengo que recorrer el hashmap? ¿Cuál es la mejor manera de hacer eso?

Nick Heiner
fuente
72
Tenga en cuenta que no hay una sola tecla correspondiente: es posible que haya varias teclas asignadas al mismo valor.
CPerkins
1
@CPerkins, pero para hashmaps como <strFilename, Reader> y muchos otros 1 a 1, es muy útil.
Aquarius Power
si tiene una pequeña colección de artículos, considere crear una constante public static final String TIME = "time";yproperties.put(TIME, PbActivityJpa_.time);
Basheer AL-MOMANI
probablemente esto podría ayudarlo a obtener los datos del mapa y también puede hacer algún tipo de procesamiento. frugalisminds.com/java/java-8-stream-map-examples
Sanjay-Dev

Respuestas:

215

Si elige usar la biblioteca de Colecciones de Commons en lugar de la API estándar de Colecciones de Java, puede lograr esto con facilidad.

La interfaz BidiMap en la biblioteca de Colecciones es un mapa bidireccional, que le permite asignar una clave a un valor (como los mapas normales), y también asignar un valor a una clave, lo que le permite realizar búsquedas en ambas direcciones. La obtención de una clave para un valor es compatible con el método getKey () .

Sin embargo, existe una advertencia: los mapas bidi no pueden tener múltiples valores asignados a claves, y por lo tanto, a menos que su conjunto de datos tenga asignaciones 1: 1 entre claves y valores, no puede usar bidimaps.

Actualizar

Si desea confiar en la API de colecciones de Java, deberá asegurarse de la relación 1: 1 entre claves y valores al momento de insertar el valor en el mapa. Esto es más fácil dicho que hecho.

Una vez que pueda asegurarse de eso, use el método entrySet () para obtener el conjunto de entradas (asignaciones) en el Mapa. Una vez que haya obtenido el conjunto cuyo tipo es Map.Entry , repita las entradas, compare el valor almacenado con el esperado y obtenga la clave correspondiente .

Actualización n. ° 2

El soporte para mapas bidireccionales con genéricos se puede encontrar en Google Guava y en las bibliotecas refactorizadas de Commons-Collections (este último no es un proyecto Apache). Gracias a Esko por señalar el soporte genérico faltante en las colecciones de Apache Commons. El uso de colecciones con genéricos hace que el código sea más fácil de mantener.

Vineet Reynolds
fuente
23
... y si le gustan los genéricos y todas esas cosas modernas, Google Collections tiene BiMap, donde puede obtener un valor específico de coincidencia de clave llamando a biMap.inverse (). get (value);
Esko el
1
Sí, Apache Commons Collections no admite genéricos. Sin embargo, existe Google Collections, como ha señalado (que todavía no uso, aún no hay una versión 1.0), y está la Commons-Collections refactorizada con soporte para Generics. Encontrará esto como un proyecto de Sourceforge @ sourceforge.net/projects/collections
Vineet Reynolds el
2
Google Collections no es una versión refactorizada de Commons-Collections.
whiskeysierra
12
@whiskeysierra: No creo que nadie lo esté diciendo (actualmente).
huff
2
Apache Collections ahora admite genéricos commons.apache.org/proper/commons-collections/javadocs/…
kervin
603

Si su estructura de datos tiene una asignación de muchos a uno entre claves y valores, debe iterar sobre las entradas y elegir todas las claves adecuadas:

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

En caso de una relación uno a uno , puede devolver la primera clave coincidente:

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

Además, para los usuarios de Guava, BiMap puede ser útil. Por ejemplo:

BiMap<Token, Character> tokenToChar = 
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
Vitalii Fedorenko
fuente
3
¿Puedes decir algo sobre la actuación? ¿Qué será más optimizado? Esto o BidiMap?
tasomaniac
He pensado la misma solución, por supuesto que la he votado pero dudo de su eficacia cuando se trata de colecciones realmente grandes.
arjacsoh
3
stackoverflow.com/questions/4553624/hashmap-get-put-complexity HashMap tiene complejidad de tiempo o(1). Si está iterando sobre los valores, matará el rendimiento. Si quieres una better performancey tiene una one-onerelación, puede usar another mapdondevalue is a key
veer7
3
Recomiendo para reemplazar .filter(entry -> entry.getValue().equals(value))con ninguna declaración sobre se hizo capacidad. Además, puede reemplazar con.filter(entry ->Objects.equals(entry.getValue(), value))null.map(entry -> entry.getKey()).map(Map.Entry::getKey)
Holger
estoy teniendo dificultades para entender la notación <T, E> antes de Set <T> getKeysByValue () ... ¿cuál es el punto ... diferente forma de hacerlo sin usar eso? gracias
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());
            }
        }
    }
}

Alguna información adicional ... Puede ser útil para usted

El método anterior puede no ser bueno si su hashmap es realmente grande. Si su mapa de hash contiene una asignación de clave única a valor único, puede mantener un mapa de hash más que contenga la asignación de Valor a Clave.

Es decir, debes mantener dos hashmaps

1. Key to value

2. Value to key 

En ese caso, puede usar el segundo hashmap para obtener la clave.

Fathah Rehman P
fuente
19

Creo que tus elecciones son

  • Use una implementación de mapa creada para esto, como el BiMap de las colecciones de google. Tenga en cuenta que las colecciones de Google BiMap requieren valores únicos, así como claves, pero proporciona un alto rendimiento en ambas direcciones.
  • Mantenga manualmente dos mapas: uno para la clave -> valor y otro mapa para el valor -> clave
  • Itere a través de entrySet()y para encontrar las claves que coinciden con el valor. Este es el método más lento, ya que requiere iterar a través de toda la colección, mientras que los otros dos métodos no lo requieren.
Chi
fuente
19

Puede insertar la clave, el par de valores y su inverso en su estructura de mapa

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

El uso de map.get ("theValue") devolverá "theKey".

Es una forma rápida y sucia de hacer mapas constantes, que solo funcionarán para unos pocos conjuntos de datos seleccionados:

  • Contiene solo 1 a 1 pares
  • El conjunto de valores es disjunto del conjunto de claves (1-> 2, 2-> 3 lo rompe)
Chicowitz
fuente
44
Esto no es realmente correcto. Esto no solo requiere 1-1, sino también que el conjunto de valores es disjunto del conjunto de claves. No puede aplicar esto al mapa biyectivo {1 -> 2, 2 -> 3}: 2 es tanto un valor como una clave.
Luis A. Florit
15

Decora el mapa con tu propia implementación

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);
    }
}
ABHI
fuente
Creo que este es un enfoque interesante, aunque dado que la relación tiene que ser 1: 1, me desharía de HashMap por completo e implementaría la interfaz Map <K, V> en su lugar para evitar duplicados de ambos, valores y claves.
Fran Marzoa
11

No hay una respuesta inequívoca, porque varias claves se pueden asignar al mismo valor. Si aplica la unicidad con su propio código, la mejor solución es crear una clase que use dos Hashmaps para rastrear las asignaciones en ambas direcciones.

recursivo
fuente
11

Para encontrar todas las claves que se asignan a ese valor, recorra todos los pares en el hashmap, usando map.entrySet().

wsorenson
fuente
44
Esta solución es terriblemente intensiva, hasta el punto de que no es práctica en HashMaps grandes.
Joehot200
10

Usando Java 8:

ftw.forEach((key, value) -> {
    if (value.equals("foo")) {
        System.out.print(key);
    }
});
phani
fuente
66
value=="foo" Esto no funcionará. equalsdebe usarse para comparar cadenas.
Anton Balaniuc
@Anton, cierto a menos que valuehaya sido internado.
frododot
9

Si construye el mapa en su propio código, intente juntar la clave y el valor en el mapa:

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

map.put(key, new KeyValue(key, value));

Luego, cuando tiene un valor, también tiene la clave.

David Tinker
fuente
3
Inteligente, pero ¿qué pasa si hay 2 o más objetos KeyValue que contienen el mismo valor? ¿Qué clave se debe elegir?
Vineet Reynolds el
2
@Vineet, no veo cómo este enfoque resuelve la pregunta del OP. ¿Qué quisiste decir con "Entonces, cuando tienes un valor, también tienes la clave"?
Qiang Li
9

Creo que esta es la mejor solución, dirección original: 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;
          }
        }

Un uso fácil: si coloca todos los datos en hasMap y tiene item = "Automobile", entonces está buscando su clave en hashMap. Esa es una buena solución.

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

Me temo que solo tendrá que iterar su mapa. Lo más corto que se me ocurrió:

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();
    }
}
André van Toly
fuente
6
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}
usuario309309
fuente
6

Parece que la mejor manera es iterar sobre las entradas usando, map.entrySet()ya que map.containsValue()probablemente lo haga de todos modos.

Jonas K
fuente
Sí, eso es exactamente lo que hace. Pero, por supuesto, devuelve verdadero tan pronto como encuentra un valor para el cual .equals es verdadero, en oposición a lo que OP probablemente necesitará hacer.
CPerkins
1
Bueno, iterar sobre las entradas puede volver con clave tan pronto como encuentre un valor coincidente también. Los partidos múltiples no parecían ser una preocupación.
Jonas K
6

Para el desarrollo de Android dirigido a API <19, la solución de relación uno a uno Vitalii Fedorenko no funciona porque Objects.equalsno está implementada. Aquí hay una alternativa 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;
}
La berga
fuente
Esta solución me funciona; también en desarrollo para una versión arqueológica de Android, en mi caso para obtener la clave de un marcador de Google Map en un mapa en un evento "onMarkerClick". Iterar la entrada Set funciona; pero iterar las claves y relacionarlas con las entradas con get (), y comparar la salida, no lo hizo.
Toby Wilson
3

Puedes usar lo siguiente:

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);
            }
        }
    }
}
Ganapathi Balasubramanian
fuente
Es bueno que desee proporcionar cosas útiles, pero no debe ser una respuesta de "solo código" y el código en sí tampoco debe estar lleno de olores de código.
Tom
2

Sí, debe recorrer el hashmap, a menos que implemente algo similar a lo que sugieren estas diversas respuestas. En lugar de jugar con el entrySet, solo obtendría el keySet (), iterar sobre ese conjunto y mantener la (primera) clave que le da su valor coincidente. Si necesita todas las claves que coinciden con ese valor, obviamente tiene que hacer todo.

Como sugiere Jonas, esto podría ser lo que está haciendo el método contiene valor, por lo que puede omitir esa prueba por completo y hacer la iteración cada vez (o tal vez el compilador ya eliminará la redundancia, quién sabe).

Además, en relación con las otras respuestas, si su mapa inverso parece

Map<Value, Set<Key>>

puede lidiar con asignaciones de clave-> valor no únicas, si necesita esa capacidad (desentrañándolas a un lado). Eso incorporaría bien a cualquiera de las soluciones que las personas sugieren aquí usando dos mapas.

Carl
fuente
2

Puede obtener la clave utilizando valores utilizando el siguiente código.

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

}
margus
fuente
Creo que esta respuesta podría mejorarse agregando una explicación.
Jonathan
2
-1. Lo probé Stringcomo clave y valor. Cuando llamo map.add("1", "2"); map.add("1","3");, puedo llamar map.getKey("2");y recuperar "1", aunque "1"sea ​​la clave "3".
jlordo
@Jonathan, la idea detrás de esta clase es mantener otro HashMap con las asignaciones inversas para que, además de recuperar un valor de una clave, pueda recuperar una clave de un valor. Las clases T1 y T2 son un poco confusas; tal vez, literalmente, ¿nombrarlos clave y valor? Aunque esperaría la capacidad de recibir más de un valor o más de una clave a cambio, dependiendo de los datos y lo que desee. Usar con precaución
Chicowitz
1
@theknightwhosaysni "1" ya no es la clave para "2". Esta es también la respuesta a su pregunta, las llamadas getValue("1")volverán 3.
jlordo
Lo siento jlordo, me equivoqué sobre el comportamiento estándar de Hashmap: tienes razón en que agregar un nuevo valor para una clave debería reemplazar el valor anterior
Chicowitz
2

En java8

map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
    .forEach(entry -> System.out.println(entry.getKey()));
usuario3724331
fuente
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;
}
India asombrosa
fuente
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 (mapa); System.out.println (getKey (map, "4"));
Increíble India
1
¿Qué sucede si varias claves tienen el mismo valor?
Cà phê đen
Cuando pasa las claves múltiples tienen el mismo valor, obtendremos la última clave como resultado. ejemplo: salida A 1, B 1, C 1, D 2: si pasamos el valor 1, la salida será C
Amazing India
@AmazingIndia Esto no está garantizado y depende completamente de la implementación específica del mapa. HashMap, por ejemplo, no garantiza un pedido, por lo que no tiene idea de qué salida se devolverá aquí.
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
     */
}
Kanagavelu Sugumar
fuente
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;
}
kanaparthikiran
fuente
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);
    }
}
Madhav
fuente
1

Use una envoltura delgada: 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;
   }
}
Jayen
fuente
1

Mis 2 centavos Puede obtener las claves en una matriz y luego recorrerla en bucle. Esto afectará el rendimiento de este bloque de código si el mapa es bastante grande, en el que primero obtiene las claves en una matriz que puede consumir algo de tiempo y luego está haciendo un bucle. De lo contrario, para mapas más pequeños, debería estar bien.

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)            
}
Manu Bhat
fuente
¿Y por qué alguien debería usar ese enfoque? Como ya dijo, el rendimiento sería peor que en otros enfoques.
Tom
1

Creo que keySet () puede ser bueno para encontrar la asignación de claves al valor y tener un mejor estilo de codificación que entrySet () .

Ex:

Suponga que tiene un mapa HashMap , ArrayList res , un valor en el que desea encontrar toda la asignación de claves , luego almacene las claves en la resolución .

Puedes escribir el código a continuación:

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

en lugar de usar entrySet () a continuación:

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

Espero eso ayude :)

FrancisGeek
fuente
map.get(key) == valueno es una buena idea al verificar la igualdad de objetos, ya que está comparando referencias. La igualdad de objetos siempre debe usar su.equals()
frododot
1

Si bien esto no responde directamente a la pregunta, está relacionado.

De esta manera, no necesita seguir creando / iterando. Simplemente cree un mapa inverso una vez y obtenga lo que necesita.

/**
 * 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;
}
Markymark
fuente
0

Es importante tener en cuenta que desde esta pregunta, Apache Collections admite BidiMaps genéricos . Entonces, algunas de las respuestas más votadas ya no son precisas en ese punto.

Para un BidiMap serializado que también admite valores duplicados (escenario 1 a muchos), también considere MapDB.org .

Kervin
fuente
0
  1. Si desea obtener la clave del valor, lo mejor es usar bidimap (mapas bidireccionales), puede obtener la clave del valor en el tiempo O (1).

    Pero, el inconveniente de esto es que solo puede usar un conjunto de claves y valores únicos.

  2. Hay una estructura de datos llamada Table en java, que no es más que un mapa de mapas como

    Tabla <A, B, C> == mapa <A, mapa <B, C>>

    Aquí puede obtener map<B,C>mediante consultas T.row(a);, y también puede obtener map<A,C>mediante consultasT.column(b);

En su caso especial, inserte C como una constante.

Entonces, es como <a1, b1, 1> <a2, b2, 1>, ...

Entonces, si encuentra a través de T.row (a1) ---> devuelve el mapa de -> get keyset this map devuelto.

Si necesita encontrar el valor clave, T.column (b2) -> devuelve el mapa de -> obtiene el conjunto de claves del mapa devuelto.

Ventajas sobre el caso anterior:

  1. Puede usar múltiples valores.
  2. Más eficiente cuando se utilizan grandes conjuntos de datos.
hombre murciélago
fuente