web-dev-qa-db-ja.com

単一値マップへの複数のキーJava

私の質問はこれに似ていると思います: 複数のキーでマップを実装する方法? ですが、重要な違いがあります。その質問では(私の理解が正しい場合は、正しくない場合はお知らせください)、キーは常に一意であると想定されていました。 MyMapという形式のマップが欲しいのですが、キーは必ずしも一意ではありません。それが意味をなさない場合は、基本的に2次元配列が必要ですが、座標で要素を参照するのではなく、オブジェクトのペアで要素を参照します。

これが機能するライブラリまたはこれを自分で実装する良い方法のいずれかについて誰かが何かアイデアを持っていますか?ライブラリに関する限り、私はApache CommonsとGuavaを見てきましたが、どちらも私が望むものを持っていないようです。

20
Steve

Guavaの Table データ構造は、オブジェクトのペアによって値を参照するという要件を満たしているようです。

18
Mark

この答えが暴言と見なされないことを願っていますが、私が理解できる限り、箱から取り出した状態でjdkを使用して簡単な方法で実現できるものにライブラリを使用したいと思います。

とにかく、オブジェクトのペアを使用して要素にアクセスしたいということでした。次のようなキーを保持するクラスを作成できます。

public class Pair {
  // string represntation of an object
  private final String x; 
  private final String y;

  // ctor, getters...

  public int hashcode() {...}
  public boolean equals(Object other) {...}
}

hashcodeメソッドは、すべての構成要素(この場合、2つの場合はxおよびy)のハッシュコードを生成しますが、任意の数をサポートするように簡単に拡張できます。要素)、およびxyの値が同じであれば、2つのキーは同じになります。ペアの要素が単純な文字列でない場合、ほとんどすべてのオブジェクトの文字列表現を導出するのは簡単です(たとえば、toStringメソッドの適切な実装を提供します)。

アイデアは、ペアの各要素に対して一意の文字列表現を持つことです。

もちろん、確実なハッシュコードを生成することは簡単ではないので、優れたオプションは文字列を使用することです。ハッシュコードを生成するには、ペアオブジェクトの文字列表現を追加するだけです。

public int hashcode() {
  return ('x' + x + ":y" + y).hashcode();
}

セパレーターを必ず用意してください。それ以外の場合、x=ab, y=bx=a, y=bbなどの値の場合、オブジェクトが完全に異なっていても、同じハッシュコードを取得します。

また、等価性は、ペアの要素の値を調べるのと同じくらい簡単です。

public boolean equals(Object other) {
  // if other is not null and is an instance of Pair
  final Pair otherPair = (Pair)other;
  return this.x.equals(otherPair.x) && this.y.equals(otherPair.y);
}

したがって、次のようなマップでPairclassを使用できます。

final Map<Pair, Whatever> map = new Hashmap<Pair, Whatever>();
// ...

基本的に、ハッシュマップは、キーのハッシュコードを使用して、値を割り当てるバケットに決定します。 2つのキーが同じハッシュコードを持っている場合、equalsメソッドを使用して、衝突が発生したばかりか、それともsameキーであるかを判断します。

PairTreeMapクラスを使用する場合は、compareToメソッドを実装するか、そのようなをインスタンス化するときに独自のComparatorを提供する必要があります地図。 TreeMapの実装は、compareToメソッドの結果に基づいて、値を割り当てる場所を決定します。

13
chahuistle

Apache Commons Collectionには MultiKey があります。

import org.Apache.commons.collections4.keyvalue.MultiKey;

Map<MultiKey, ValueType> myMap = new HashMap<MultiKey, ValueType>();
myMap.put(new MultiKey(key1, key2), value);

myMap.get(new MultiKey(key1, key2));

これには、マップからN次元配列を作成するという利点があります。

3
adkisson

ネストされたHashMapを探しているように思えます。これはうまくいくかもしれませんが、私の内臓によれば、そのようなモンスターを実装することは、パフォーマンスと健全性の両方でひどい考えになるでしょう。

どのように初期化できますか:

    HashMap<Key1, HashMap<Key2, Value>> nestedHashMap = new HashMap<Key1, HashMap<Key2, Value>>();

値の追加:

    Key1 first;
    Key2 second;
    Value data;
    HashMap<Key2, Value> tempMap = new HashMap<Key2, Value>();
    tempMap.put(second, data);
    nestedHashMap.put(first, tempMap);

データを取り戻す:

    Key1 first;
    Key2 second;
    Value data;
    data = nestedHashMap.get(first).get(second);

免責事項:このコードはテストされていません。頭から離れてきました。

2
rjacks