Hashmap Java: Como obter a chave do valor?

450

Se eu tiver o valor "foo"e um HashMap<String> ftwpara o qual ftw.containsValue("foo")retorne true, como posso obter a chave correspondente? Preciso percorrer o hashmap? Qual o melhor jeito pra fazer isso?

Nick Heiner
fonte
72
Observe que não há uma chave correspondente única - é possível que haja várias chaves mapeadas para o mesmo valor.
CPerkins
1
@CPerkins, mas para hashmaps como <strFilename, Reader> e muitos outros 1 a 1, é muito útil.
Poder de Aquário
se você tiver uma pequena coleção de itens, considere criar constantes public static final String TIME = "time";eproperties.put(TIME, PbActivityJpa_.time);
Basheer AL-MOMANI 17/17/18
provavelmente isso pode ajudá-lo a obter os dados do mapa e você também pode executar algum tipo de processamento. frugalisminds.com/java/java-8-stream-map-examples
Sanjay-Dev

Respostas:

215

Se você optar por usar a biblioteca Commons Collections em vez da API Java Collections padrão, poderá conseguir isso com facilidade.

O BidiMap interface na biblioteca Coleções é um mapa bidirecional, permitindo mapear uma chave para um valor (como mapas normais) e também mapear um valor para uma chave, permitindo realizar pesquisas nas duas direções. A obtenção de uma chave para um valor é suportada pelo método getKey () .

No entanto, existe uma ressalva: os mapas de bidi não podem ter vários valores mapeados para chaves e, portanto, a menos que seu conjunto de dados tenha mapeamentos 1: 1 entre chaves e valores, você não pode usar bidimaps.

Atualizar

Se você deseja confiar na API Java Collections, precisará garantir o relacionamento 1: 1 entre chaves e valores no momento da inserção do valor no mapa. Isto é mais fácil dizer do que fazer.

Depois de garantir isso, use o método entrySet () para obter o conjunto de entradas (mapeamentos) no Mapa. Depois de obter o conjunto cujo tipo é Map.Entry , percorra as entradas, comparando o valor armazenado com o esperado e obtenha a chave correspondente .

Atualização # 2

O suporte para mapas bidi com genéricos pode ser encontrado no Google Guava e nas bibliotecas Commons-Collections refatoradas (o último não é um projeto Apache). Agradecemos a Esko por apontar o suporte genérico ausente no Apache Commons Collections. O uso de coleções com genéricos torna o código mais sustentável.

Vineet Reynolds
fonte
23
... e se você gosta de genéricos e todo esse material moderno, o Google Collections possui o BiMap, onde você pode obter o valor especificado correspondente à chave, chamando biMap.inverse (). get (value);
Esko
1
Sim, o Apache Commons Collections não suporta genéricos. No entanto, existe o Google Collections, como você apontou (que ainda não uso - ainda não há versão 1.0), e há o Commons-Collections refatorado com suporte para genéricos. Você vai encontrar isso como um projeto Sourceforge @ sourceforge.net/projects/collections
Vineet Reynolds
2
As coleções do Google não são uma versão refatorada do Commons-Collections.
Whiskeyierra
12
@whiskeysierra: Acho que ninguém está dizendo atualmente.
huff
2
O Apache Collections agora suporta genéricos commons.apache.org/proper/commons-collections/javadocs/…
kervin
603

Se sua estrutura de dados possui mapeamento muitos-para-um entre chaves e valores, você deve iterar sobre as entradas e escolher todas as chaves adequadas:

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

No caso de um relacionamento individual, você pode retornar a primeira chave correspondente:

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

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

Além disso, para usuários do Guava, o BiMap pode ser útil. Por exemplo:

BiMap<Token, Character> tokenToChar = 
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
Vitalii Fedorenko
fonte
3
Você pode dizer algo sobre o desempenho? O que será mais otimizado? Este ou BidiMap?
tasomaniac
Eu pensei na mesma solução, eu a votei naturalmente, mas duvido de sua eficiência quando se trata de coleções realmente grandes.
arjacsoh
3
stackoverflow.com/questions/4553624/hashmap-get-put-complexity O HashMap possui complexidade de tempo o(1). Se você estiver iterando sobre os valores, isso prejudicará o desempenho. Se você quiser um better performancee tem um one-onerelacionamento, você pode usar another mapondevalue is a key
veer7
3
Eu recomendo para substituir .filter(entry -> entry.getValue().equals(value))com nenhuma declaração sobre a capacidade foi feita. Além disso, você pode substituir por.filter(entry ->Objects.equals(entry.getValue(), value))null.map(entry -> entry.getKey()).map(Map.Entry::getKey)
Holger
Estou tendo dificuldade para entender a notação <T, E> antes de Set <T> getKeysByValue () ... qual é o sentido .... maneira diferente de fazer isso sem usar isso? agradecimentos
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());
            }
        }
    }
}

Algumas informações adicionais ... Pode ser útil para você

O método acima pode não ser bom se o seu hashmap for realmente grande. Se o seu hashmap contiver uma chave exclusiva para o mapeamento de valor exclusivo, você poderá manter mais um hashmap que contenha o mapeamento de Valor para Chave.

Ou seja, você tem que manter dois hashmaps

1. Key to value

2. Value to key 

Nesse caso, você pode usar o segundo hashmap para obter a chave.

Fathah Rehman P
fonte
19

Eu acho que suas escolhas são

  • Use uma implementação de mapa criada para isso, como o BiMap das coleções do Google. Observe que o BiMap das coleções do Google requer valores exclusivos, além de chaves, mas fornece alto desempenho no desempenho de ambas as direções
  • Manter manualmente dois mapas - um para chave -> valor e outro mapa para valor -> chave
  • Faça uma iteração entre entrySet()e para encontrar as chaves que correspondem ao valor. Esse é o método mais lento, pois requer iteração em toda a coleção, enquanto os outros dois métodos não exigem isso.
Chi
fonte
19

Você pode inserir o par de chave, valor e seu inverso na estrutura do mapa

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

O uso de map.get ("theValue") retornará "theKey".

É uma maneira rápida e suja de criar mapas constantes, que só funcionarão para alguns poucos conjuntos de dados selecionados:

  • Contém apenas 1 a 1 pares
  • O conjunto de valores é separado do conjunto de teclas (1-> 2, 2-> 3 o quebra)
Chicowitz
fonte
4
Isso não está realmente correto. Isso não requer apenas 1 a 1, mas também que o conjunto de valores é separado do conjunto de chaves. Você não pode aplicar isso ao mapa bijetivo {1 -> 2, 2 -> 3}: 2 é um valor e uma chave.
Luis A. Florit 04/02
15

Decore o mapa com sua própria implementação

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
fonte
Eu acho que essa é uma abordagem interessante, mas, como a relação tem que ser 1: 1, eu me livraria completamente do HashMap e implementaria a interface Map <K, V> para evitar duplicatas de valores e chaves.
Fran Marzoa
11

Não há resposta inequívoca, porque várias chaves podem ser mapeadas para o mesmo valor. Se você estiver aplicando exclusividade com seu próprio código, a melhor solução é criar uma classe que use dois Hashmaps para rastrear os mapeamentos nas duas direções.

recursivo
fonte
11

Para encontrar todas as chaves que são mapeadas para esse valor, itere através de todos os pares no hashmap, usando map.entrySet().

Wsorenson
fonte
4
Essa solução é terrivelmente intensiva, a ponto de ser impraticável em HashMaps grandes.
Joehot200
10

Usando o Java 8:

ftw.forEach((key, value) -> {
    if (value.equals("foo")) {
        System.out.print(key);
    }
});
phani
fonte
6
value=="foo" isso não vai funcionar. equalsdeve ser usado para comparar seqüências de caracteres.
Anton Balaniuc
@Anton, verdadeiro, a menos que valuetenha sido internado.
Frododot 14/11/19
9

Se você criar o mapa em seu próprio código, tente colocar a chave e o valor no mapa juntos:

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

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

Então, quando você tem um valor, você também tem a chave.

David Tinker
fonte
3
Inteligente, mas e se houver 2 ou mais objetos KeyValue que contenham o mesmo valor? Qual chave você deve escolher?
Vineet Reynolds
2
@ Vinine, não vejo como essa abordagem resolve a questão do OP. o que você quis dizer com "Então, quando você tem um valor, você também tem a chave".
Qiang Li
9

Eu acho que esta é a melhor solução, endereço 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;
          }
        }

Um uso fácil: se você colocar todos os dados no hasMap e tiver o item = "Automobile", estará procurando a chave no hashMap. essa é uma boa solução.

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

Receio que você apenas precise iterar seu mapa. O mais curto que eu consegui:

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
fonte
6
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}
user309309
fonte
6

Parece que a melhor maneira é iterar as entradas usando, map.entrySet()já que map.containsValue()provavelmente faz isso de qualquer maneira.

Jonas K
fonte
Sim, é exatamente isso que faz. Mas é claro que ele retorna verdadeiro assim que encontra um valor para o qual .equals é verdadeiro, em oposição ao que o OP provavelmente precisará fazer.
cperkins
1
Bem, a iteração nas entradas pode retornar com a chave assim que encontrar um valor correspondente também. Várias correspondências não pareciam ser uma preocupação.
Jonas K
6

Para a API de segmentação de desenvolvimento para Android <19, a solução de relacionamento individual Vitalii Fedorenko não funciona porque Objects.equalsnão foi implementada. Aqui está uma alternativa simples:

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;
}
The Berga
fonte
Esta solução funciona para mim; também desenvolvendo para uma versão arqueológica do Android, no meu caso, para obter a chave de um marcador do Google Map em um mapa em um evento "onMarkerClick". Iterar o entrySet funciona; mas iterar as chaves e combiná-las às entradas com get () e comparar a saída, não.
Toby Wilson
3

Você pode usar o abaixo:

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
fonte
É bom que você queira fornecer coisas úteis, mas não deve ser uma resposta "apenas código" e o código em si também não deve estar cheio de odores de código.
Tom
2

Sim, você precisa percorrer o hashmap, a menos que implemente algo ao longo do que essas várias respostas sugerem. Em vez de mexer com o entrySet, eu apenas pegaria o keySet (), iteraria sobre esse conjunto e manteria a (primeira) chave que fornece seu valor correspondente. Se você precisar de todas as chaves que correspondam a esse valor, obviamente precisará fazer a coisa toda.

Como Jonas sugere, isso já pode ser o que o método containsValue está fazendo, portanto, você pode pular esse teste todos juntos e fazer a iteração sempre (ou talvez o compilador já elimine a redundância, quem sabe).

Além disso, em relação às outras respostas, se o seu mapa reverso parecer

Map<Value, Set<Key>>

você pode lidar com mapeamentos de chave-> valor não exclusivos, se precisar dessa capacidade (desmembrando-os). Isso seria incorporado em qualquer uma das soluções sugeridas pelas pessoas aqui usando dois mapas.

Carl
fonte
2

Você pode obter a chave usando valores usando o seguinte 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
fonte
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
fonte
Eu acho que essa resposta poderia ser melhorada adicionando uma explicação.
Jonathan
2
-1. Eu testei com Stringcomo chave e valor. Quando ligo map.add("1", "2"); map.add("1","3");, posso ligar map.getKey("2");e recuperar "1", mesmo que "1"seja a chave "3".
jlordo
@ Jonathan, a idéia por trás dessa classe é manter outro HashMap com os mapeamentos reversos para que, além de recuperar um valor de uma chave, você possa recuperar uma chave de um valor. As classes T1 e T2 são um pouco confusas; talvez literalmente os chame de Chave e Valor? Embora eu esperasse a capacidade de receber mais de um valor ou mais de uma chave em troca, dependendo dos dados e do que você deseja. Use com cautela
Chicowitz
1
@theknightwhosaysni "1" não é a chave para "2" (mais). Essa também é a resposta para sua pergunta, a chamada getValue("1")retornará 3.
jlordo
Desculpe jlordo, eu estava enganado sobre o comportamento padrão do Hashmap: você está certo ao adicionar um novo valor para uma chave substituir o valor antigo #
Chicowitz 27/10/2014
2

Em java8

map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
    .forEach(entry -> System.out.println(entry.getKey()));
user3724331
fonte
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;
}
Amazing India
fonte
Map <String, Inteiro> map = new HashMap <String, Inteiro> (); map.put ("A", 1); map.put ("B", 2); map.put ("C", 3); map.put ("D", 4); // System.out.println (mapa); System.out.println (getKey (mapa, "4"));
Incrível India
1
O que acontece se várias chaves tiverem o mesmo valor?
Cà phê em
Quando você passar as várias chaves com o mesmo valor, obteremos a última chave como resultado. exemplo: Uma saída 1, B 1, C 1, D 2: se passarmos o valor 1, a saída será C
Amazing India
@AmazingIndia Isso não é garantido e depende completamente da implementação específica do mapa. O HashMap, por exemplo, não garante um pedido; portanto, você não tem idéia de qual saída será retornada aqui.
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
fonte
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
fonte
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
fonte
1

Use um invólucro fino: 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
fonte
1

Meus 2 centavos. Você pode obter as chaves em uma matriz e depois percorrer a matriz. Isso afetará o desempenho desse bloco de código se o mapa for muito grande, onde você está obtendo as chaves em uma matriz primeiro, o que pode consumir algum tempo e, em seguida, você faz um loop. Caso contrário, para mapas menores, tudo ficará bem.

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
fonte
E por que alguém deveria usar essa abordagem? Como você já disse, o desempenho seria pior do que em outras abordagens.
Tom
1

Eu acho que keySet () pode ser bom para encontrar as chaves mapeadas para o valor e ter um estilo de codificação melhor do que entrySet () .

Ex:

Suponha que você tenha um mapa HashMap , ArrayList res , um valor para o qual deseja encontrar todo o mapeamento de chaves e, em seguida, armazene as chaves nos res .

Você pode escrever o código abaixo:

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

em vez de usar entrySet () abaixo:

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

Espero que ajude :)

FrancisGeek
fonte
map.get(key) == valuenão é uma boa ideia ao verificar a igualdade de objetos, pois você está comparando referências. Igualdade do objeto deve sempre usar o seu.equals()
frododot
1

Embora isso não responda diretamente à pergunta, está relacionado.

Dessa forma, você não precisa continuar criando / iterando. Basta criar um mapa reverso uma vez e obter o que você precisa.

/**
 * 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
fonte
0

É importante observar que, desde esta pergunta, o Apache Collections suporta BidiMaps genéricos . Portanto, algumas das principais respostas votadas não são mais precisas nesse ponto.

Para um BidiMap serializado que também suporta valores duplicados (cenário de 1 para muitos), considere o MapDB.org .

Kervin
fonte
0
  1. Se você deseja obter a chave do valor, é melhor usar o bidimapa (mapas bidirecionais), é possível obter a chave do valor no tempo O (1).

    Mas a desvantagem disso é que você só pode usar um conjunto de chaves e um conjunto de valores exclusivos.

  2. Existe uma estrutura de dados chamada Tabela em java, que nada mais é do que mapa de mapas como

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

    Aqui você pode map<B,C>consultar T.row(a);, e também map<A,C>consultarT.column(b);

No seu caso especial, insira C como uma constante.

Então, é como <a1, b1, 1> <a2, b2, 1>, ...

Portanto, se você encontrar via T.row (a1) ---> retorna o mapa de -> obtenha o conjunto de chaves deste mapa retornado.

Se você precisar encontrar o valor da chave, T.column (b2) -> retorna o mapa de -> obtém o conjunto de chaves do mapa retornado.

Vantagens em relação ao caso anterior:

  1. Pode usar vários valores.
  2. Mais eficiente ao usar grandes conjuntos de dados.
homem Morcego
fonte