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




como se (25)

  1. Si desea obtener la clave del valor, lo mejor es utilizar bidimap (mapas bidireccionales), puede obtener la clave del valor en O (1) vez.

    Pero, el inconveniente de esto es que solo puede usar conjuntos de valores y conjuntos de teclas únicos.

  2. Hay una estructura de datos llamada Tabla 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 el map<B,C> consultando T.row(a); , y también puede obtener el map<A,C> consultando T.column(b);

En su caso especial, inserte C como alguna constante.

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

Por lo tanto, si encuentra vía T.row (a1) ---> devuelve el mapa de -> obtener keyset este mapa devuelto.

Si necesita encontrar un valor clave, T.column (b2) -> devuelve el mapa de -> obtener 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.

Si tengo el valor "foo" y un HashMap<String> ftw para el cual 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?


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


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 pones todos los datos en hasMap y tienes item = "Automobile", entonces estás buscando su clave en hashMap. Esa es una buena solución.

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

Si su estructura de datos tiene una asignación de muchos a uno entre claves y valores, debe repetir las entradas y seleccionar 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 el 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 guayaba, 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);

Utilizando Java 8:

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

Para la API de desarrollo de Android <19, la solución de relación uno a uno de Vitalii Fedorenko no funciona porque Objects.equals no está implementado. 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;
}

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

Parece que la mejor forma de hacerlo es iterar sobre las entradas usando map.entrySet() ya que map.containsValue() probablemente haga esto de todos modos.


Si crea 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 tienes un valor, también tienes la clave.


Puede obtener la clave usando los valores usando 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);

Mis 2 centavos. Puede obtener las claves en una matriz y luego hacer un ciclo a través de la matriz. Esto afectará el rendimiento de este bloque de código si el mapa es bastante grande, donde en primer lugar está obteniendo las claves en una matriz, lo que puede consumir algo de tiempo y luego se está realizando un ciclo. 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)            
}

Si elige utilizar la biblioteca de colecciones de Commons en lugar de la API de colecciones de Java estándar, puede lograrlo 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 a un valor de 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, hay una advertencia, los mapas bidi no pueden tener múltiples valores asignados a las claves y, por lo tanto, a menos que su conjunto de datos tenga asignaciones 1: 1 entre las claves y los valores, no puede usar los mapas de bid.

Actualizar

Si desea confiar en la Java Collections API, deberá garantizar la relación 1: 1 entre las claves y los 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 (mapeos) en el Mapa. Una vez que haya obtenido el conjunto cuyo tipo es Map.Entry , Map.Entry las entradas, compare el valor almacenado con el esperado y obtenga la clave correspondiente .

Actualización # 2

El soporte para mapas bidi con genéricos se puede encontrar en Google Guava y en las bibliotecas de las Commons-Collections refactored (esta última no es un proyecto de Apache). Gracias a Esko por señalar el soporte genérico faltante en Apache Commons Collections. Usar colecciones con genéricos hace que el código sea más mantenible.


Puede utilizar el 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);
            }
        }
    }
}

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

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

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

De esta manera no necesitas seguir creando / iterando. Solo crea un mapa inverso una vez y obtén lo que necesitas.

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

Puede insertar la clave, el par de valores y su inverso en la estructura de su 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 está separado del conjunto de claves (1-> 2, 2-> 3 lo rompe)

Es importante tener en cuenta que, desde esta pregunta, las colecciones Apache son compatibles con los commons.apache.org/proper/commons-collections/javadocs/… . Así que 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 de 1 a muchos) también considere MapDB.org .


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

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

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 tu hashmap es realmente grande. Si su hashmap contiene una clave única para un mapeo de valor único, puede mantener un hashmap más que contenga una correlación de Value to Key.

Es decir, hay que mantener dos hashmaps.

1. Key to value

2. Value to key 

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


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

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

En java8

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

Como mucha gente lo mencionó antes, Java siempre es pasado por valor

Aquí hay otro ejemplo que le ayudará a comprender la diferencia ( el ejemplo de intercambio clásico ):

public class Test {
  public static void main(String[] args) {
    Integer a = new Integer(2);
    Integer b = new Integer(3);
    System.out.println("Before: a = " + a + ", b = " + b);
    swap(a,b);
    System.out.println("After: a = " + a + ", b = " + b);
  }

  public static swap(Integer iA, Integer iB) {
    Integer tmp = iA;
    iA = iB;
    iB = tmp;
  }
}

Huellas dactilares:

Antes: a = 2, b = 3
Después: a = 2, b = 3

Esto sucede porque iA y iB son nuevas variables de referencia local que tienen el mismo valor de las referencias pasadas (apuntan a y b respectivamente). Por lo tanto, intentar cambiar las referencias de iA o iB solo cambiará en el ámbito local y no fuera de este método.







java hashmap