web-dev-qa-db-ja.com

Java Hashmap:値からキーを取得する方法

値が"foo"で、ftw.containsValue("foo")trueを返すHashMap<String> ftwがある場合、対応するキーを取得するにはどうすればよいですか。ハッシュマップをループする必要がありますか?そのための最善の方法は何ですか?

405
Nick Heiner

標準のJava Collections APIの代わりに Commons Collections library を使用することを選択した場合は、これを簡単に実現できます。

Collectionsライブラリの BidiMap インターフェースは双方向マップであり、キーを値に(法線マップのように)マッピングしたり、値をキーにマッピングしたりすることができます。両方向のルックアップ値のキーを取得することは getKey()メソッド でサポートされています。

警告はしかしあり、双方向のマップは、キーにマッピングされた複数の値を持つことができない、とあなたのデータセットが1持っていない限り、それ故に:キーと値の間に1のマッピングを、あなたはbidimapsを使用することはできません。

更新

マップに値を挿入する際のキーと値の間に1の関係:あなたは、JavaコレクションAPIに依存したい場合は、1を確保する必要があります。これは言うは易く行うは難しです。

それが確認できたら、 entrySet()メソッド を使用してMap内の一連のエントリ(マッピング)を取得します。型が Map.Entry のセットを取得したら、エントリを繰り返して 格納された値 を期待値と比較し、 対応するキー を取得します。

更新#2

総称による双方向マップのサポートは Google Guava およびリファクタリングされた Commons-Collections ライブラリにあります(後者はApacheプロジェクトではありません)。 Apacheのコモンズコレクションに欠けている一般的なサポートを指摘しエスコに感謝します。ジェネリックとコレクションを使用すると、より保守コードになります。

203
Vineet Reynolds

データ構造にキーと値の間に 多対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);
582
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());
            }
        }
    }
}

追加情報...あなたに役立つかもしれません

あなたのハッシュマップが本当に大きいなら、上記の方法は良くないかもしれません。ハッシュマップに一意のキーから一意の値へのマッピングが含まれている場合は、ValueからKeyへのマッピングを含むハッシュマップをもう1つ管理できます。

つまり、2つのハッシュマップを管理する必要があります。

1. Key to value

2. Value to key 

その場合は、2番目のハッシュマップを使ってキーを取得できます。

71
Fathah Rehman P

キー、値のペア、およびその逆の両方をマップ構造に挿入できます。

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

Map.get( "theValue")を使用すると、 "theKey"が返されます。

それは私がコンスタントマップを作った迅速で汚い方法です、そしてそれは選ばれた少数のデータセットのためにだけ働くでしょう:

  • 1対1ペアのみ
  • 値のセットはキーのセットから分離しています(1 - > 2、2 - > 3はそれを中断します)
18
Chicowitz

あなたの選択は

  • Googleコレクションの BiMap のように、このために構築されたマップ実装を使用してください。グーグルコレクションのBiMapはキーだけでなくユニークな値を必要としますが、両方向で高いパフォーマンスを提供します。
  • 手動で2つのマップ(キー - >値用、および値 - >キー用)を1つずつ管理します。
  • entrySet()を繰り返して、値に一致するキーを見つけます。コレクション全体を反復処理する必要があるため、これは最も遅い方法ですが、他の2つの方法では必要ありません。
18
Chi

独自の実装で地図を飾ります

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);
    }
}
14
ABHI

複数のキーが同じ値にマップできるため、明確な答えはありません。あなた自身のコードで独自性を強制している場合、最善の解決策は2つのHashmapを使って両方向のマッピングを追跡するクラスを作成することです。

11
recursive

その値に対応するすべてのキーを見つけるには、map.entrySet()を使用して、ハッシュマップ内のすべてのペアを反復処理します。

11
wsorenson

私はこれが最善の解決策だと思います、元のアドレス: 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;
          }
        }

使い方が簡単:すべてのデータをhasMapに格納していて、item = "Automobile"の場合は、そのキーをhashMapで探しています。それが良い解決策です。

getKeyFromValue(hashMap, item);
System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item));
8
boy

自分のコードでマップを作成する場合は、キーと値を一緒にマップに入れてみてください。

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

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

それからあなたが価値を持っているとき、あなたは鍵も持っています。

7
David Tinker
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}
6
user309309

map.entrySet()はおそらくこれを行うので、map.containsValue()を使用してエントリを反復処理するのが最善の方法のようです。

6
Jonas Klemming

マップを繰り返すだけでいいのですが。私が思い付くことができる最短:

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();
    }
}
6
André van Toly

Java 8を使用する場合

ftw.forEach((key, value) -> {
    if (value=="foo") {
        System.out.print(key);
    }
});
5
phani

API <19を対象としたAndroid開発では、Objects.equalsが実装されていないため、Vitalii Fedorenkoの一対一のリレーションシップソリューションは機能しません。これは簡単な代替案です:

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;
}
5
The Berga

あなたは以下を使うことができます:

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);
            }
        }
    }
}
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;
}
2
Amazing India

次のコードを使って値を使ってキーを取得できます。

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);
2
Amit

Java 8では

map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
    .forEach(entry -> System.out.println(entry.getKey()));
2
user3724331
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);
    }

}
2
margus
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
     */
}
1

私の2セントキーを配列で取得してから、その配列をループ処理することができます。マップがかなり大きい場合、これはこのコードブロックのパフォーマンスに影響を及ぼします。最初に配列内のキーを取得するため、しばらく時間がかかり、その後ループすることになります。それ以外の小さい地図では大丈夫です。

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)            
}
1
Manu Bhat
/**
 * 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;
}
1
kanaparthikiran

薄いラッパーを使う: 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;
   }
}
1
Jayen
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);
    }
}
1
Madhav

そうです、あなたがハッシュマップをループしなければならないのです。 entrySetをいじるのではなく、単にkeySet()を取得し、そのセットを反復処理して、一致する値を取得する(最初の)キーをそのまま使用します。その値に一致するすべてのキーが必要な場合は、明らかにすべてをやらなければなりません。

Jonasが示唆しているように、これはすでにcontainsValueメソッドが行っていることである可能性があるので、そのテストをすべてまとめてスキップし、毎回繰り返しを実行することができます。

逆マップが次のようになっている場合は、他の回答との関係で、

Map<Value, Set<Key>>

その機能が必要な場合は、一意でないキー→値のマッピングに対処することができます(それらを脇に解くことはできません)。これは、2つのマップを使用してここで提案されているソリューションのいずれにもうまく組み込まれます。

1
Carl

これは直接質問に答えるものではありませんが、関連しています。

このようにして、作成/反復を続ける必要はありません。リバースマップを一度作成して、必要なものを入手するだけです。

/**
 * 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;
}
1
Markymark
  1. 値からキーを取得したい場合は、bidimap(双方向マップ)を使用するのが最善ですが、O(1) timeの値からキーを取得できます。

    しかし、これの欠点は、一意のキーセットと値セットしか使用できないことです。

  2. Javaには Table と呼ばれるデータ構造がありますが、これはマップのマップに他なりません。

    テーブル<A、B、C> ==マップ<A、マップ<B、C>>

    ここでT.row(a);を照会することでmap<B,C>を取得することができ、またT.column(b);を照会することでmap<A,C>を取得することができます。

特別な場合には、定数としてCを挿入してください。

したがって、<a1、b1、1> <a2、b2、1>、...のようになります。

したがって、T.row(a1)を介して検索した場合--->のマップが返されます - >キーセットの取得この返されたマップ。

もしあなたがキーの値を見つける必要があるなら、T.column(b2) - >のマップを返す - >返されたマップのキーセットを取得する。

前のケースに対する利点:

  1. 複数の値を使用できます。
  2. 大規模なデータセットを使用するとより効率的です。
0
Batman

値をmaxValueにします。

Set keySet = map.keySet();

keySet.stream().filter(x->map.get(x)==maxValue).forEach(x-> System.out.println(x));
0
Shivendra Gupta

これを試して:

static String getKeyFromValue(LinkedHashMap<String, String> map,String value) {
    for (int x=0;x<map.size();x++){
        if( String.valueOf( (new ArrayList<String>(map.values())).get(x) ).equals(value))
            return String.valueOf((new ArrayList<String>(map.keySet())).get(x));
    }
    return null;
}
0
programmer

keySet() はキーの値へのマッピングを見つけるのに適していて、 entrySet() よりも優れたコーディングスタイルを持っていると思います。

例:

HashMap map 、ArrayList res value にしたい すべてのキーへのマッピング へのキーの格納、そして へのキーの格納res .

あなたは以下のコードを書くことができます:

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

以下のentrySet()を使うよりはむしろ:

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

それが役に立てば幸い :)

0
FrancisGeek

この質問以来、Apache Collectionsは Generic BidiMaps をサポートしています。そのため、投票された回答の中には、その時点では正確ではないものがあります。

重複値(1対多のシナリオ)もサポートする直列化BidiMapの場合は、 MapDB.org も検討してください。

0
kervin

私が知っている限りでは、HashMapのキーと値は、それらを配列として表すときに混在しません。

hashmap.values().toArray()

そして

hashmap.keySet().toArray()

したがって、次のコード(Java 8以降)は期待通りに動作するはずです。

public Object getKeyByFirstValue(Object value) {
    int keyNumber =  Arrays.asList(hashmap.values().toArray()).indexOf(value);
    return hashmap.keySet().toArray()[keyNumber];
}

ただし、( WARNING! )反復よりも2〜3倍遅くなります。

0
MilTy