10

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に置き換えることができれば節約できるメモリを不必要に取ります(新しいインスタンスはGCの対象になります)。それらは同じですが、古いインスタンスを再利用するとメモリが節約されます。list.add(key)list.add(map.getKey(key))

キーを値に埋め込むか、グアバの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問題は、パッケージのプライベート メソッドを使用するため、配置する必要があることです。このような方法を使用するのは危険な場合がありますが、私の「1 回実行」のユース ケースでは問題ありません。

4

8 に答える 8

9

これを行うために、どれだけの悪を犯す準備ができていますか?

インターフェイスでは、Mapキーまたはエントリを取得できません。Setインターフェイスも同様です。HashMapのパブリック インターフェイスも同様です。

しかし、HashMapパッケージインターフェイスは (少なくとも Sun JDK では) 機能します。ソースコードを見てください。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 メンテナーは将来このメソッドを削除する可能性があり、すべてのプラットフォームに存在するわけではない可能性がありますが、リスクを冒して鼻をかむ準備ができている場合、これは簡単な解決策です。

于 2012-10-07T15:23:24.217 に答える
3

NavigableMapがあります。これを使用すると、返されたキーをceilingKey使用equalsして、その正確なキーのエントリがあるかどうかを確認できます。ただし、HashMapを使用することはできません。TreeMapなどが必要であり、メモリパフォーマンスの利点が失われる可能性があります(キーを実装する必要がありますComparable)。また、javadocは、返されたキーがマップで使用されているものとまったく同じオブジェクトであるかどうかを示していないため、実装固有である可能性があります。

于 2012-10-07T15:39:36.337 に答える
1

編集:あなたがやりたいと思うことは、 akey-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

于 2012-10-07T14:22:02.093 に答える
0

エントリーセットが欲しいらしい。

for (Entry<Key,Value> entry : map.entrySet()) {
    if (something(entry.getKey(), entry.getValue())) {
        list.add(entry.getKey());
    }
}

取得したデータに関する情報を活用せずに、それ以上の成果を上げることはできません。

さらに、API ドキュメントはあなたの味方です。

于 2012-10-07T14:39:17.660 に答える
0

が必要な場合はKey、次のValue3 つの可能性があります。

  1. キー セットを繰り返し処理し、値のキーを見つけます (ランタイムが悪い)。
  2. 元のマップに加えて逆マップを保存します (値 -> キー) (2 倍のスペース消費)
  3. HashBiMapメソッドを持つGuava を使用しinverseます。マップの逆を返します。inverse.get(value)次に、 を使用してキーを取得するだけです。
于 2012-10-07T14:58:43.120 に答える
0

このようにアプローチすることをお勧めします。

    for (Iterator i = map.keySet().iterator(); i.hasNext();) {
        String key = (String) i.next();
        if (key.equals(value)) {
            ....
        }
    }
于 2012-10-07T14:25:14.760 に答える