【发布时间】:2010-11-25 21:49:33
【问题描述】:
如果我有值"foo",以及ftw.containsValue("foo") 返回true 的HashMap<String> ftw,我怎样才能得到对应的密钥?我必须遍历哈希图吗?最好的方法是什么?
【问题讨论】:
-
请注意,没有一个对应的键 - 很可能有多个键映射到同一个值。
如果我有值"foo",以及ftw.containsValue("foo") 返回true 的HashMap<String> ftw,我怎样才能得到对应的密钥?我必须遍历哈希图吗?最好的方法是什么?
【问题讨论】:
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
*/
}
【讨论】:
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();
}
}
【讨论】:
在java8中
map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
.forEach(entry -> System.out.println(entry.getKey()));
【讨论】:
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);
}
}
【讨论】:
String 作为键和值对其进行了测试。当我调用map.add("1", "2"); map.add("1","3"); 时,我可以调用map.getKey("2"); 并检索"1",即使"1" 是"3" 的键。
getValue("1") 将返回3。
您可以使用以下代码使用值获取密钥..
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);
【讨论】:
恐怕您只需要迭代您的地图。我能想到的最短的:
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();
}
}
【讨论】:
是的,您必须遍历哈希图,除非您按照这些不同答案的建议来实现某些东西。与其摆弄 entrySet,我只需获取 keySet(),迭代该集合,并保留为您提供匹配值的(第一个)键。如果您需要与该值匹配的所有键,显然您必须完成所有操作。
正如 Jonas 建议的那样,这可能已经是 containsValue 方法正在做的事情,因此您可以完全跳过该测试,并且每次都进行迭代(或者编译器可能已经消除了冗余,谁知道呢) .
此外,相对于其他答案,如果您的反向地图看起来像
Map<Value, Set<Key>>
如果您需要该功能(将它们放在一边),您可以处理非唯一键-> 值映射。这可以很好地融入人们在这里使用两张地图提出的任何解决方案中。
【讨论】:
如果您在自己的代码中构建地图,请尝试将地图中的键和值放在一起:
public class KeyValue {
public Object key;
public Object value;
public KeyValue(Object key, Object value) { ... }
}
map.put(key, new KeyValue(key, value));
那么当你有一个值时,你也有这个键。
【讨论】:
没有明确的答案,因为多个键可以映射到同一个值。如果您使用自己的代码强制执行唯一性,最好的解决方案是创建一个使用两个 Hashmap 来跟踪双向映射的类。
【讨论】: