有没有办法如何从HashMap
(或其他合适的Map
)有效获取密钥(或整个条目)?
在有人说之前,我从不需要它:我做到了。我有这样的循环
for (long i=0; i<1e12; ++i) {
Key key = new Key(i);
Value value = map.get(key);
if (something(key, value)) list.add(key);
}
和我的key
不必要地占用内存,如果我可以用list.add(key)
替换list.add(map.getKey(key))
(新实例符合GC条件),则可以保存。 虽然它们是相同的,但重复使用旧实例会节省内存。
我知道我可以将密钥嵌入到值中或使用Guava的Interner
;两者都有帮助,但两者都需要一些记忆。
解决一些误解评论:如果效率没有问题,可以采取以下措施
Key getKeyFromMap(Key key, Map<Key, ?> map) {
for (Key key2 : map.keySet()) {
if (key.equals(key2)) return key2;
}
return null;
}
接受答案中描述的最有效的解决方案:
public static <K, V> K getKey(K key, HashMap<K, V> map) {
final Entry<K, V> entry = map.getEntry(key);
return entry==null ? null : entry.getKey();
}
问题是它必须放在package java.util
中,因为它使用了包私有方法。使用这种方法可能很危险,但在我的“一次性运行”用例中没有问题。
答案 0 :(得分:7)
为了做到这一点,你准备承诺多少邪恶?
Map
界面不允许您检索密钥或条目。 Set
界面也没有。 HashMap
的公共界面也不是。
但是HashMap
的包接口(至少在Sun JDK中)。看看the source code;在第355行,有一个名为getEntry
的方法,它的开头如下:
/**
* Returns the entry associated with the specified key in the
* HashMap. Returns null if the HashMap contains no mapping
* for the key.
*/
final Entry<K,V> getEntry(Object key) {
我相信这正是你所需要的。你可以用反射来调用它,或者将你自己的类隐藏到java.util
包中。 Java维护者将来可以采用这种方法,并且它可能不会出现在所有平台上,但是如果你准备好嗤之以鼻并承担风险,那么这是一个简单的解决方案。
答案 1 :(得分:3)
NavigableMap
有ceilingKey
,您可以在返回的密钥上使用equals
来查看是否有该确切密钥的条目。但你不能使用HashMap,你需要TreeMap或其他东西,这可能会抵消任何内存性能优势(你的密钥需要实现Comparable
)。此外,javadoc没有说明返回的键是否与Map中使用的完全相同的对象,因此它可能是特定于实现的。
答案 2 :(得分:1)
修改:如果key-Object
是您Map
中的关键字,我认为您要做的就是测试内存效率:
Key getKeyFromMap(Key key, Map<Key, ?> map) {
if(map.containsKey(key){
return key;
}else{
return null;
}
}
旧答案:
Map<String, Value> map = new HashMap<>();//Java 7 diamond operator.
Set<String> keySet = map.keySet();
for(String key: keySet){
System.out.println(key + " is key in the map");
}
Object[] keyArray = keySet.toArray();
Map#keySet()
会返回包含地图中所有已使用键的Set
。你可以遍历你的Set。不会像Map
那样订购套装。但是你可以将它转换为一个数组,Set#toArray()
返回一个可以转换为Set
的泛型类型的对象数组。
答案 3 :(得分:1)
我找到了另一种解决方法,利用了集合(或映射)中元素(或键)比较的实现。
java {util中的所有集合(或映射)实现(据我所知)在o.equals(e)
是用户搜索对象时按o
比较元素。所以我提出了以下解决方案:
public static <K> K getOriginalKey(final Map<K, ?> map, final K key) {
OriginalElementExtractor extractor = new OriginalElementExtractor(key);
map.containsKey(extractor);
return (K) extractor.result;
}
public static <E> E getOriginalElement(final Collection<E> coll, final E element) {
OriginalElementExtractor extractor = new OriginalElementExtractor(element);
coll.contains(extractor);
return (E) extractor.result;
}
private static class OriginalElementExtractor {
final Object key;
final int hash;
Object result;
OriginalElementExtractor(final Object key) {
this.key = key;
hash = key.hashCode();
}
@Override
public boolean equals(final Object o) {
boolean eq;
if (eq = key.equals(o))
result = o;
return eq;
}
@Override
public int hashCode() {
return hash;
}
}
Collection(或map)将调用OriginalElementExtractor.equals(Object)
方法来检查是否相等,并且将传递原始元素。
答案 4 :(得分:0)
我建议你这样做。
for (Iterator i = map.keySet().iterator(); i.hasNext();) {
String key = (String) i.next();
if (key.equals(value)) {
....
}
}
答案 5 :(得分:0)
你想要输入设置。
for (Entry<Key,Value> entry : map.entrySet()) {
if (something(entry.getKey(), entry.getValue())) {
list.add(entry.getKey());
}
}
如果不利用有关您所获得数据的一些信息,您将不会比这更好。
此外,API documentation是您的朋友。
答案 6 :(得分:0)
如果您需要Key
到给定Value
,则有三种可能性:
inverse
的番石榴HashBiMap
。它将返回地图的反转。然后,您只需使用inverse.get(value)
获取密钥。答案 7 :(得分:0)
我还没有找到一个好的解决方案,所以请按如下所示将密钥嵌入值中:
Map<K, Entry<K, V>> map = new HashMap<K, Entry<K, V>>();
K key = new K(...);
map.put(key, new AbstractMap.SimpleEntry<K, V>(key, value));
//then I can retrieve the reference of original key, given another instance of de key
Entry<K, V> keyObj = map.get(new K(...));