Перейти к основному содержимому

Получить ключ для значения из карты Java

· 4 мин. чтения

1. Введение

В этом кратком руководстве мы продемонстрируем три различных подхода к извлечению ключа из карты для заданного значения. Мы также обсудим положительные и отрицательные стороны различных решений.

Чтобы узнать больше об интерфейсе карты , вы можете прочитать эту статью .

2. Итеративный подход

Интерфейс карты Java Collections предлагает метод с именем entrySet() . Он возвращает все записи или пары ключ-значение карты в наборе .

Идея состоит в том, чтобы перебрать этот набор записей и вернуть ключ, для которого значение соответствует предоставленному значению:

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

Однако может существовать вероятность того, что несколько ключей указывают на одно и то же значение.

В этом случае, если найдено совпадающее значение, мы добавляем ключ в набор и продолжаем цикл. В итоге возвращаем Set , содержащий все нужные ключи:

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

Хотя это очень простая реализация, она сравнивает все записи, даже если все совпадения найдены после нескольких итераций.

3. Функциональный подход

С введением лямбда-выражений в Java 8 мы можем сделать это более гибким и удобочитаемым способом. Мы преобразуем набор записей в поток и предоставляем лямбду для фильтрации только тех записей с заданным значением.

Затем мы используем метод карты, чтобы вернуть поток ключей из отфильтрованных записей:

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

Преимущество возврата потока заключается в том, что он может удовлетворить широкий спектр потребностей клиентов. Вызывающий код может потребовать только один ключ или все ключи, указывающие на предоставленное значение. Поскольку оценка потока выполняется лениво, клиент может контролировать количество итераций в зависимости от своих требований.

Кроме того, клиент может преобразовать поток в любую коллекцию, используя соответствующий сборщик:

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

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

4. Использование коллекций Apache Commons

Приведенные выше идеи не будут очень полезны , если нам нужно очень часто вызывать функции для конкретной карты . Он будет без необходимости повторять набор своих ключей снова и снова.

В этом сценарии сохранение другого сопоставления значений с ключами было бы более целесообразным, поскольку для извлечения ключа для значения потребуется постоянное время.

Библиотека Commons Collections от Apache предоставляет такую двунаправленную карту под названием BidiMap . У него есть метод getKey() для получения ключа для заданного значения:

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

Однако BidiMap устанавливает отношение 1:1 между своими ключами и значениями . Если мы попытаемся поместить пару ключ-значение, для которой значение уже существует на карте, старая запись будет удалена. Другими словами, он обновляет ключ по значению.

Кроме того, требуется больший объем памяти для хранения обратной карты.

Более подробная информация о том, как использовать BidiMap , содержится в этом руководстве .

5. Использование Google Гуавы

Мы можем использовать другую двунаправленную карту под названием BiMap, найденную в Guava, разработанную Google. Этот класс предоставляет метод с именем inverse() для получения Карты ключа значения или обратной Карты для выборки ключа на основе заданного значения:

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

Как и BidiMap , BiMap также не позволяет использовать несколько ключей, ссылающихся на одно и то же значение . Если мы попытаемся сделать такую попытку, будет выброшено исключение java.lang.IllegalArgumentException .

Излишне говорить, что BiMap также использует значительный объем памяти, так как он должен хранить обратную карту внутри. Если вам интересно узнать больше о BiMap , вы можете ознакомиться с этим руководством .

6. Заключение

В этой краткой статье мы обсудили некоторые методы получения ключа карты по заданному значению. Каждый подход имеет свои плюсы и минусы. Мы всегда должны рассматривать варианты использования и выбирать наиболее подходящий в зависимости от ситуации.

Полный исходный код приведенного выше руководства доступен на GitHub .