有没有办法从“地图”中获取密钥(或整个条目)?

时间:2012-10-07 14:18:23

标签: java map

有没有办法如何从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中,因为它使用了包私有方法。使用这种方法可能很危险,但在我的“一次性运行”用例中没有问题。

8 个答案:

答案 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)

NavigableMapceilingKey,您可以在返回的密钥上使用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,则有三种可能性:

  1. 遍历密钥集并找到值的关键字(运行时错误)。
  2. 除原始地图外还保存逆映射(值 - &gt;键)(双倍空间消耗)
  3. 使用方法为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(...));