Obter a chave para um valor em um mapa Java

Obter a chave para um valor em um mapa Java

 

1. Introdução

In this quick tutorial, we’re going to demonstrate three different approaches for retrieving the key from a map for a given value.  Também discutiremos os pontos positivos e negativos das várias soluções.

Para saber mais sobre a interfaceMap, você pode verificarthis article.

2. Uma abordagem iterativa

A interfaceMap deJava Collections oferece um método chamadoentrySet(). Ele retorna todas as entradas ou pares de valores-chave do mapa emSet.

A ideia é iterar sobre esse conjunto de entrada e retornar a chave para a qual o valor corresponde ao valor fornecido:

public  K getKey(Map map, V value) {
    for (Entry entry : map.entrySet()) {
        if (entry.getValue().equals(value)) {
            return entry.getKey();
        }
    }
    return null;
}

No entanto, pode haver uma possibilidade de várias chaves estarem apontando para o mesmo valor.

Nesse caso, se um valor correspondente for encontrado, adicionamos a chave aSete continuamos o loop. No final, retornamos oSet contendo todas as chaves desejadas:

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

Embora esta seja uma implementação muito direta,it compares all the entries even if all matches are found after a few iterations.

3. Uma abordagem funcional

With the introduction of Lambda Expressions in Java 8, we can do it in a more flexible and readable way. Convertemos o conjunto de entradas emStreame fornecemos um lambda para filtrar apenas as entradas com o valor fornecido.

Em seguida, usamos o método map para retornarStream das chaves das entradas filtradas:

public  Stream keys(Map map, V value) {
    return map
      .entrySet()
      .stream()
      .filter(entry -> value.equals(entry.getValue()))
      .map(Map.Entry::getKey);
}

The advantage of returning a stream is that it can cater to a wide range of client needs. O código de chamada pode exigir apenas uma tecla ou todas as teclas apontando para o valor fornecido. Como a avaliação de um fluxo é lenta, o cliente pode controlar o número de iterações com base em seus requisitos.

Além disso, o cliente pode converter o fluxo em qualquer coleção usando um coletor apropriado:

Stream keyStream1 = keys(capitalCountryMap, "South Africa");
String capital = keyStream1.findFirst().get();

Stream keyStream2 = keys(capitalCountryMap, "South Africa");
Set capitals = keyStream2.collect(Collectors.toSet());

4. Usando coleções do Apache Commons

As ideias acima não seriam muito úteisif we need to call the functions very frequently for a particular map. Iterará desnecessariamente o conjunto de suas chaves repetidamente.

Neste cenário,maintaining another map of value to the keys would make more sense as it will take constant time to retrieve the key for a value.

A bibliotecaCommons Collections porApache fornece umMap bidirecional chamadoBidiMap. Ele tem um método chamadogetKey() para recuperar uma chave para um determinado valor:

BidiMap capitalCountryMap = new DualHashBidiMap<>();
capitalCountryMap.put("Berlin", "Germany");
capitalCountryMap.put("Cape Town", "South Africa");
String capitalOfGermany = capitalCountryMap.getKey("Germany");

No entanto,BidiMap imposes a 1:1 relationship between its keys and values. Se tentarmos colocar um par de valores-chave para o qual o valor já existe emMap,, ele remove a entrada antiga. Em outras palavras, ele atualiza a chave com relação ao valor.

Além disso, requer uma quantidade maior de memória para manter o mapa reverso.

Mais detalhes sobre como usar umBidiMap estão emthis tutorial.

5. Usando o Google Guava

We may use another bi-directional Map called BiMap found in Guava developed by Google. Esta classe fornece um método chamadoinverse() para obter a chave de valorMap ou oMap reverso para obter a chave com base em um determinado valor:

HashBiMap capitalCountryMap = HashBiMap.create();
capitalCountryMap.put("Berlin", "Germany");
capitalCountryMap.put("Cape Town", "South Africa");
String capitalOfGermany = capitalCountryMap.inverse().get("Germany");

ComoBidiMap,BiMap also doesn’t allow multiple keys referring to the same value. Se tentarmos fazersuch an attempt, it lançar umjava.lang.IllegalArgumentException.

Não é preciso dizer queBiMap também usa uma quantidade significativa de memória, pois precisa armazenar o mapa inverso dentro. Se você estiver interessado em saber mais sobreBiMap, você pode verificarthis tutorial.

6. Conclusão

Neste breve artigo, discutimos alguns métodos de recuperação de uma chaveMap’s dado o valor. Cada abordagem tem seus próprios prós e contras. Sempre devemos considerar os casos de uso e escolher o mais apropriado com base na situação.

O código-fonte completo para o tutorial acima está disponívelover on GitHub.