Java Hashmap: comment obtenir la clé à partir de la valeur?
si j'ai la valeur "foo"
, et un HashMap<String> ftw
pour lequel ftw.containsValue("foo")
retourne true
, Comment puis-je obtenir la clé correspondante? Dois-je faire une boucle à travers le hashmap? Quelle est la meilleure façon de le faire?
30 réponses
si vous choisissez d'utiliser la Commons Collections library au lieu de L'API Java Collections standard, vous pouvez y parvenir facilement.
l'interface BidiMap dans la bibliothèque des Collections est une carte bidirectionnelle, vous permettant de mapper une clé à une valeur (comme des cartes normales), et aussi de mapper une valeur à une clé, vous permettant ainsi d'effectuer des recherches dans les deux directions. L'obtention d'une clé pour une valeur est soutenue par le méthode getKey () .
il y a une mise en garde cependant, bidi maps ne peut pas avoir des valeurs multiples mappées sur des clés, et donc à moins que votre ensemble de données ait des mappages 1:1 entre les clés et les valeurs, vous ne pouvez pas utiliser bidimaps.
mise à Jour
si vous voulez vous fier à L'API Java Collections, vous devez vous assurer de la relation 1:1 entre les clés et les valeurs au moment d'insérer la valeur dans le cartographie. C'est plus facile à dire qu'à faire.
une fois que vous pouvez vous assurer que, Utilisez la méthode entrySet () pour obtenir l'ensemble des entrées (mappings) dans la carte. Une fois que vous avez obtenu l'ensemble dont le type est carte.Entrée , itérer à travers les entrées, en comparant la valeur stockée contre les attendus, et obtenir la clé correspondante .
mise à Jour #2
Support pour les cartes bidi avec génériques peut être trouvé dans Google Guava et le refactored Commons-Collections bibliothèques (ce dernier n'est pas un projet Apache). Merci à Esko d'avoir souligné l'absence de support générique dans les Collections Apache Commons. L'utilisation de collections avec des génériques rend le code plus maintenable.
si votre structure de données a plusieurs à un correspondance entre les clés et les valeurs, vous devriez itérer au-dessus des entrées et choisir toutes les clés appropriées:
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;
}
dans le cas de one-to-one relation, vous pouvez retourner la première clé appariée:
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());
}
aussi, pour les utilisateurs de goyave, BiMap peut être utile. Exemple:
BiMap<Token, Character> tokenToChar =
ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
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());
}
}
}
}
quelques informations supplémentaires... Peut vous être utile
méthode ci-dessus peut ne pas être bon si votre hashmap est vraiment grand. Si votre hashmap contient une clé unique à la cartographie de valeur unique, vous pouvez maintenir un hashmap de plus qui contient la cartographie de valeur à clé.
C'est-à-dire que vous devez maintenir deux hachmaps
1. Key to value
2. Value to key
dans ce cas, vous pouvez utiliser second hashmap pour obtenir la clé.
vous pouvez insérer à la fois la clé, la paire de valeur et son inverse dans votre structure de carte
map.put("theKey", "theValue");
map.put("theValue", "theKey");
utilisant la carte.get ("theValue") retournera alors"theKey".
c'est un moyen rapide et sale que j'ai fait des cartes constantes, qui ne fonctionneront que pour quelques ensembles de données sélectionnés:
- contient seulement 1 à 1 paire
- ensemble de valeurs est disjoint de l'ensemble des clés (1->2, 2->3 151990920"
je pense que vos choix sont
- utilisez une implémentation de carte construite pour cela, comme le BiMap des collections google. Notez que les collections google BiMap nécessite uniqueless de valeurs, ainsi que des clés, mais il fournit de hautes performances dans les deux sens de la performance
- gérer manuellement deux cartes-une pour la clé - > valeur, et une autre pour la valeur - > clé
-
entrySet()
et de trouver les clés qui correspondent à la valeur. C'est la méthode la plus lente, car elle nécessite d'itérer à travers toute la collection, alors que les deux autres méthodes ne nécessitent pas cela.
pour trouver toutes les clés qui correspondent à cette valeur, itérez toutes les paires dans le hashmap, en utilisant map.entrySet()
.
il n'y a pas de réponse univoque, car plusieurs clés peuvent correspondre à la même valeur. Si vous appliquez unique-ness avec votre propre code, la meilleure solution est de créer une classe qui utilise deux Hashmaps pour suivre les correspondances dans les deux sens.
Décorez la carte avec votre propre implémentation
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);
}
}
je pense que c'est la meilleure solution, l'adresse originale: 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;
}
}
une utilisation facile: si vous mettez toutes les données dans hasMap et que vous avez item = "Automobile", vous cherchez donc sa clé dans hashMap. c'est une bonne solution.
getKeyFromValue(hashMap, item);
System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item));
si vous construisez la carte dans votre propre code, essayez de mettre la clé et la valeur dans la carte ensemble:
public class KeyValue {
public Object key;
public Object value;
public KeyValue(Object key, Object value) { ... }
}
map.put(key, new KeyValue(key, value));
alors quand vous avez une valeur, vous avez aussi la clé.
je crains que vous n'ayez juste à itérer votre carte. Le plus court que j'ai pu trouver:
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();
}
}
for(int key: hm.keySet()) {
if(hm.get(key).equals(value)) {
System.out.println(key);
}
}
il semble que le meilleur moyen est pour vous d'itérer sur les entrées en utilisant map.entrySet()
depuis map.containsValue()
fait probablement cela de toute façon.
Utilisant Java 8:
ftw.forEach((key, value) -> {
if (value=="foo") {
System.out.print(key);
}
});
pour Développement Android ciblant API < 19, Vitalii Fedorenko solution de relation un-à-un ne fonctionne pas parce que Objects.equals
n'est pas mis en œuvre. Voici une alternative 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;
}
vous pouvez utiliser ce qui suit:
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);
}
}
}
}
vous pouvez obtenir la clé en utilisant des valeurs en utilisant le code suivant..
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);
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);
}
}
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;
}
Oui, vous devez faire une boucle à travers le hashmap, à moins que vous ne mettiez en œuvre quelque chose dans le sens de ce que ces différentes réponses suggèrent. Plutôt que de jouer avec l'entrySet, j'obtiendrais simplement le keySet(), itérerais sur cet ensemble, et garderais la (première) clé qui vous donne votre valeur correspondante. Si vous avez besoin de toutes les clés qui correspondent à cette valeur, évidemment vous devez faire toute la chose.
comme Jonas le suggère, c'est peut-être déjà ce que fait la méthode containsValue, donc vous pouvez simplement sauter ce test tout ensemble, et juste faire l'itération à chaque fois (ou peut-être que le compilateur éliminera déjà la redondance, qui sait).
aussi, par rapport aux autres réponses, si votre carte ressemble à
Map<Value, Set<Key>>
vous pouvez traiter avec non-unique clé->les correspondances de valeur, si vous avez besoin de cette capacité (les démêler de côté). Cela incorporerait fine dans n'importe laquelle des solutions que les gens suggèrent ici en utilisant deux cartes.
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
*/
}
/**
* 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;
}
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);
}
}
utiliser un emballage fin: 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;
}
}
mes 2 cents. Vous pouvez obtenir les clés dans un tableau et ensuite une boucle sur le tableau. Cela affectera la performance de ce bloc de code si la carte est assez grande , où dans vous obtenez les clés dans un tableau d'abord qui pourrait prendre un certain temps et puis vous êtes en boucle. Sinon pour des cartes plus petites il devrait être ok.
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)
}
bien que cela ne réponde pas directement à la question, c'est lié.
de Cette façon, vous n'avez pas besoin de continuer à créer/itération. Il suffit de créer une carte inverse une fois et obtenir ce dont vous avez besoin.
/**
* 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;
}
Dans java8
map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
.forEach(entry -> System.out.println(entry.getKey()));
il est important de noter que depuis cette question, Apache Collections supporte Bidimaps Générique . Ainsi, quelques-unes des meilleures réponses votées ne sont plus exactes sur ce point.
pour une image bidimensionnelle sérialisée qui supporte aussi les valeurs dupliquées (scénario de 1 à plusieurs), considérez aussi MapDB.org .
-
si vous voulez obtenir la clé de value, son meilleur pour utiliser bidimap (bi-directional maps) , vous pouvez obtenir la clé de value en O(1) Temps.
mais, l'inconvénient avec ceci est que vous ne pouvez utiliser que des clés et des valeurs uniques.
-
il existe une structure de données appelée Table en java, qui n'est rien d'autre qu'une carte de cartes comme
Table < A, B, C > == carte < a, carte < B, C > >
ici vous pouvez obtenir
map<B,C>
en demandantT.row(a);
, et vous pouvez aussi obtenirmap<A,C>
en demandantT.column(b);
Dans votre cas particulier, insérez C comme une constante.
ainsi, il comme < a1, b1, 1 > < a2 , b2, 1 >,...
Donc, si vous trouvez via T. ligne(a1) ---> retourne la carte de --> obtenir keyset cette retourné la carte.
si vous avez besoin de trouver une valeur clé, alors, T. colonne(b2) --> retourne la carte de --> récupérez la clé de la carte retournée.
avantages par rapport au cas précédent:
- Peut utiliser plusieurs valeurs.
- Plus efficace lors de l'utilisation de grands ensembles de données.
je pense keySet() peut-être bien de trouver les clés de la cartographie de la valeur, et d'avoir un meilleur style de codage que entrySet() .
Ex:
supposez que vous avez un HashMap carte , ArrayList res , un valeur vous voulez trouver toute la clé mapping to, puis stocker les clés de la res .
vous pouvez écrire le code ci-dessous:
for (int key : map.keySet()) {
if (map.get(key) == value) {
res.add(key);
}
}
plutôt que d'utiliser entrySet() ci-dessous:
for (Map.Entry s : map.entrySet()) {
if ((int)s.getValue() == value) {
res.add((int)s.getKey());
}
}
Espère que cela aide :)