値とを返す"foo"
aがある場合、対応するキーを取得するにはどうすればよいですか? ハッシュマップをループする必要がありますか? それを行う最善の方法は何ですか?HashMap<String> ftw
ftw.containsValue("foo")
true
39 に答える
データ構造にキーと値の間に多対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;
}
1 対 1 の関係の場合、最初に一致したキーを返すことができます。
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);
標準の Java Collections フレームワークの代わりにCommons Collections ライブラリを使用することを選択した場合、これを簡単に実現できます。
コレクション ライブラリのBidiMap
インターフェイスは双方向マップであり、キーを値にマップしたり (法線マップと同様)、値をキーにマップしたりできるため、双方向でルックアップを実行できます。値のキーの取得は、getKey()
メソッドによってサポートされています。
ただし、Bidi マップは複数の値をキーにマッピングすることはできないため、データ セットでキーと値が 1:1 でマッピングされていない限り、Bidi マップを使用できないことに注意してください。
Java Collections API に依存する場合は、値をマップに挿入するときに、キーと値の間の 1:1 の関係を確認する必要があります。これは言うは易く行うは難しです。
確認できたら、entrySet()
メソッドを使用してマップ内の一連のエントリ (マッピング) を取得します。タイプが のセットを取得したらMap.Entry
、エントリを反復処理し、保存された値を期待値と比較して、対応するキーを取得します。
ジェネリックを使用した双方向マップのサポートは、 Google GuavaおよびリファクタリングされたCommons-Collectionsライブラリで見つけることができます (後者は Apache プロジェクトではありません)。Apache Commons Collections に欠けている一般的なサポートを指摘してくれた Esko に感謝します。ジェネリクスでコレクションを使用すると、より保守しやすいコードが作成されます。
バージョン 4.0 以降、公式の Apache Commons Collections™ ライブラリはジェネリックをサポートしています。
現在 Javaジェネリックをサポートしているおよびインターフェースの利用可能な実装のリストについては、「 org.apache.commons.collections4.bidimap 」パッケージの要約ページを参照してください。BidiMap
OrderedBidiMap
SortedBidiMap
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 つ保持できます。
つまり、2 つのハッシュマップを維持する必要があります。
1. Key to value
2. Value to key
その場合、2 番目のハッシュマップを使用してキーを取得できます。
キーと値のペアとその逆の両方をマップ構造に挿入できます
map.put("theKey", "theValue");
map.put("theValue", "theKey");
map.get("theValue") を使用すると、"theKey" が返されます。
一定のマップを作成したのは、手早く汚い方法で、選択した少数のデータセットでのみ機能します。
- 1 対 1 のペアのみを含む
- 値のセットがキーのセットから切り離されています (1->2、2->3 はそれを壊します)
あなたの選択は
- Google コレクションのBiMapなど、このために構築されたマップ実装を使用します。Google コレクションの BiMap では、一意でない値とキーが必要ですが、双方向のパフォーマンスで高いパフォーマンスが得られることに注意してください。
- 2 つのマップを手動で維持する - 1 つはキー -> 値用、もう 1 つは値 -> キー用
- と を反復して
entrySet()
、値に一致するキーを見つけます。コレクション全体を反復処理する必要があるため、これは最も遅い方法ですが、他の 2 つの方法では必要ありません。
独自の実装でマップを装飾する
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);
}
}
これが最善の解決策だと思います。元のアドレス: 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));
複数のキーが同じ値にマップされる可能性があるため、明確な答えはありません。独自のコードで一意性を強制する場合、最善の解決策は、2 つのハッシュマップを使用して双方向のマッピングを追跡するクラスを作成することです。
その値にマップされるすべてのキーを見つけるには、 を使用して、ハッシュマップ内のすべてのペアを反復処理しますmap.entrySet()
。
独自のコードでマップを作成する場合は、キーと値を一緒にマップに入れてみてください。
public class KeyValue {
public Object key;
public Object value;
public KeyValue(Object key, Object value) { ... }
}
map.put(key, new KeyValue(key, value));
次に、値がある場合は、キーもあります。
残念ながら、マップを反復するだけで済みます。私が思いつくことができる最短:
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);
}
}
API < 19 をターゲットとする Android 開発の場合、Vitalii Fedorenko の 1 対 1 の関係ソリューションはObjects.equals
実装されていないため機能しません。簡単な代替手段を次に示します。
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;
}
おそらくとにかくこれを行うmap.entrySet()
ので、エントリを繰り返し処理するのが最善の方法のように思えます。map.containsValue()
以下を使用できます。
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);
}
}
}
}
次のコードを使用して値を使用してキーを取得できます。
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);
}
}
薄いラッパーを使用: 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;
}
}
java8で
map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
.forEach(entry -> System.out.println(entry.getKey()));
はい、これらのさまざまな回答が示唆することに沿って何かを実装しない限り、ハッシュマップをループする必要があります。entrySet をいじるのではなく、keySet() を取得し、そのセットを反復処理して、一致する値を取得する (最初の) キーを保持します。その値に一致するすべてのキーが必要な場合は、明らかにすべてを行う必要があります。
Jonas が示唆するように、これは既に containsValue メソッドが行っていることかもしれないので、そのテストをすべてスキップして、毎回反復を実行するだけかもしれません (または、コンパイラーが冗長性を既に排除しているかもしれません)。
また、他の回答と比較して、逆マップが次のように見える場合
Map<Value, Set<Key>>
その機能が必要な場合は、一意ではないキー->値マッピングを処理できます(それらを脇に置きます)。これは、ここで 2 つのマップを使用して提案されているソリューションのいずれにもうまく組み込まれます。
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);
}
}
私の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 つのキーに対して複数の値を処理できます (BidiMap とは異なります)。
public static List<String> getKeysByValue(Map<String, String> map, String value) {
List<String> list = map.keySet().stream()
.collect(groupingBy(k -> map.get(k))).get(value);
return (list == null ? Collections.emptyList() : list);
}
1:1 マッピングのマッピングをList
含む を取得します 返されるリストは1 または 1 を含みますkey(s)
value
empty
value
値からキーを取得する場合は、 bidimap (双方向マップ) を使用するのが最適です。O(1) 時間で値からキーを取得できます。
ただし、これの欠点は、一意のキーセットと値セットしか使用できないことです。
JavaにはTableというデータ構造がありますが、これはマップのマップに他なりません
Table< A, B, C > == マップ < A , マップ < B, C > >
ここでは、クエリを実行して取得できます。また、
map<B,C>
クエリを実行して取得するT.row(a);
こともできますmap<A,C>
T.column(b);
特殊なケースでは、 C を定数として挿入します。
つまり、 < a1, b1, 1 > < a2, b2 , 1 > , ... のようになります。
したがって、T.row(a1) 経由で見つかった場合 ---> マップを返します --> この返されたマップのキーセットを取得します。
キー値を見つける必要がある場合は、 T.column(b2) --> マップを返します --> 返されたマップのキーセットを取得します。
前のケースに対する利点:
- 複数の値を使用できます。
- 大規模なデータ セットを使用する場合により効率的です。
私が知る限り、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];
}
ただし、(警告! ) 反復よりも 2 ~ 3 倍遅くなります。
Iterator<Map.Entry<String,String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String,String> entry = iterator.next();
if (entry.getValue().equals(value_you_look_for)) {
String key_you_look_for = entry.getKey();
}
}