Вопрос-ответ

Java Hashmap: How to get key from value?

Java Hashmap: как получить ключ из значения?

Если у меня есть значение "foo", и HashMap<String> ftw для которого ftw.containsValue("foo") возвращаетсяtrue, как я могу получить соответствующий ключ? Должен ли я перебирать хэш-карту? Как лучше всего это сделать?

Переведено автоматически
Ответ 1

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

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

В случае однозначного отношения вы можете вернуть первый совпадающий ключ:

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

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

Также для пользователей Guava может быть полезен BiMap. Например:

BiMap<Token, Character> tokenToChar = 
ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
Ответ 2

Если вы решите использовать библиотеку коллекций Commons вместо стандартной платформы Java Collections framework, вы сможете добиться этого с легкостью.

BidiMap Интерфейс библиотеки Collections представляет собой двунаправленную карту, позволяющую сопоставлять ключ со значением (например, карты нормалей), а также сопоставлять значение с ключом, что позволяет выполнять поиск в обоих направлениях. Получение ключа для значения поддерживается getKey() методом.

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


Если вы хотите полагаться на Java Collections API, вам нужно будет обеспечить соотношение 1: 1 между ключами и значениями во время вставки значения в карту. Это легче сказать, чем сделать.

Как только вы сможете убедиться в этом, используйте entrySet() метод для получения набора записей (сопоставлений) на карте. После того, как вы получили набор, тип которого Map.Entry, выполните итерацию по записям, сравнивая сохраненное значение с ожидаемым, и получите соответствующий ключ.


Поддержку карт bidi с обобщениями можно найти в Google Guava и переработанных библиотеках Commons-Collections (последняя не является проектом Apache). Спасибо Esko за указание на отсутствие универсальной поддержки в коллекциях Apache Commons. Использование коллекций с универсальными файлами делает код более удобным в обслуживании.


Начиная с версии 4.0 официальная библиотека Apache Commons Collections ™ поддерживает generics.

Смотрите на странице резюме пакета "org.apache.commons.collections4.bidimap" список доступных реализаций BidiMap, OrderedBidiMap и SortedBidiMap интерфейсов, которые теперь поддерживают дженерики Java.

Ответ 3
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());
}
}
}
}

Некоторая дополнительная информация... Может быть вам полезна

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

То есть вы должны поддерживать две хэш-карты

1. Key to value

2. Value to key

В этом случае вы можете использовать вторую hashmap для получения ключа.

Ответ 4

Вы могли бы вставить как пару ключ-значение, так и обратную ей в вашу структуру карты

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

Использование map.get("theValue") вернет "theKey".

Это быстрый и грязный способ создания постоянных карт, который будет работать только для нескольких избранных наборов данных:


  • Содержит только пары от 1 до 1

  • Набор значений не пересекается с набором ключей (1->2, 2->3 разбивает его)

java