web-dev-qa-db-ja.com

2つのキー(キーペア、値)でHashMapを作成する方法は?

整数の2D配列があります。それらをHashMapに入れてほしい。しかし、配列インデックスに基づいてHashMapの要素にアクセスしたいと思います。何かのようなもの:

A [2] [5]の場合、map.get(2,5)は、そのキーに関連付けられた値を返します。しかし、キーのペアでhashMapを作成するにはどうすればよいですか?または一般的に、複数のキー:Map<((key1, key2,..,keyN), Value) get(key1、key2、... keyN)を使用して要素にアクセスできる方法で。

編集:質問を投稿してから3年後、もう少し追加したい

NxN matrixの別の方法に出会いました。

配列インデックスiおよびjは、次の方法で単一のkeyとして表すことができます。

int key = i * N + j;
//map.put(key, a[i][j]); // queue.add(key); 

そして、この方法でkeyからインデックスを取得できます:

int i = key / N;
int j = key % N;
108
Crocode

いくつかのオプションがあります:

2次元

地図の地図

Map<Integer, Map<Integer, V>> map = //...
//...

map.get(2).get(5);

ラッパーキーオブジェクト

public class Key {

    private final int x;
    private final int y;

    public Key(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Key)) return false;
        Key key = (Key) o;
        return x == key.x && y == key.y;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }

}

ここでは、equals()hashCode()の実装が重要です。次に、単に使用します:

Map<Key, V> map = //...

そして:

map.get(new Key(2, 5));

Table グアバから

Table<Integer, Integer, V> table = HashBasedTable.create();
//...

table.get(2, 5);

Tableは、マップのマップを使用します。

N次元

特別なKeyクラスがn次元にスケーリングする唯一のアプローチであることに注意してください。次のことも検討してください。

Map<List<Integer>, V> map = //...

しかし、それはパフォーマンスの観点からもひどいし、読みやすさと正確さ(リストのサイズを強制する簡単な方法ではありません)。

タプルとcaseクラスが存在するScalaを見てください(Keyクラス全体をワンライナーに置き換えてください)。

179

独自のキーペアオブジェクトを作成する場合、いくつかのことに直面する必要があります。

まず、hashCode()equals()の実装に注意する必要があります。これを行う必要があります。

第二に、hashCode()を実装するときは、それがどのように機能するかを理解してください。指定されたユーザーの例

public int hashCode() {
    return this.x ^ this.y;
}

実際にできる最悪の実装の1つです。理由は簡単です:あなたは同等のハッシュをたくさん持っています!また、hashCode()は、まれで、最適な場合に一意になる傾向があるint値を返す必要があります。次のようなものを使用します。

public int hashCode() {
  return (X << 16) + Y;
}

これは高速で、-2 ^ 16〜2 ^ 16-1(-65536〜65535)のキーに対して一意のハッシュを返します。これはほとんどすべての場合に当てはまります。ごくまれに、この範囲を超えています。

第三に、equals()を実装するときは、それがオブジェクトであるため、それが何に使用されるかを知っており、キーの作成方法に注意してください。文が原因で常に同じ結果が得られる場合は、多くの場合、不要です。

次のようなキーを作成する場合は、map.put(new Key(x,y),V);キーの参照を比較することはありません。原因は、マップにアクセスするたびに、map.get(new Key(x,y));のようなことをすることです。したがって、equals()にはif (this == obj)のようなステートメントは必要ありません。 never発生します。

if (getClass() != obj.getClass())equals()の代わりに、if (!(obj instanceof this))を使用することをお勧めします。サブクラスに対しても有効です。

したがって、比較する必要があるのは実際にはXとYだけです。したがって、この場合の最適なequals()実装は次のようになります。

public boolean equals (final Object O) {
  if (!(O instanceof Key)) return false;
  if (((Key) O).X != X) return false;
  if (((Key) O).Y != Y) return false;
  return true;
}

最終的に、キークラスは次のようになります。

public class Key {

  public final int X;
  public final int Y;

  public Key(final int X, final int Y) {
    this.X = X;
    this.Y = Y;
  }

  public boolean equals (final Object O) {
    if (!(O instanceof Key)) return false;
    if (((Key) O).X != X) return false;
    if (((Key) O).Y != Y) return false;
    return true;
  }

  public int hashCode() {
    return (X << 16) + Y;
  }

}

ディメンションインデックスXおよびYには、最終的なものであり、機密情報が含まれていないため、パブリックアクセスレベルを指定できます。 privateObjectにキャストするときに、Keyアクセスレベルがanyの場合に正しく機能するかどうかは100%わかりません。

ファイナルについて疑問がある場合は、インスタンス化時に設定され、変更されない値をファイナルとして宣言します。したがって、オブジェクト定数です。

19
chrixle

複数のキーを持つハッシュマップを作成することはできませんが、キーとして複数のパラメーターを取るオブジェクトを作成することはできます。

Xとyの値を取るIndexというオブジェクトを作成します。

public class Index {

    private int x;
    private int y;

    public Index(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        return this.x ^ this.y;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Index other = (Index) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }
}

次に、HashMap<Index, Value>を使用して結果を取得します。 :)

6
Brad

Common-collectionsで実装 MultiKeyMap

5

2つの可能性。組み合わせたキーを使用します:

class MyKey {
    int firstIndex;
    int secondIndex;
    // important: override hashCode() and equals()
}

または地図の地図:

Map<Integer, Map<Integer, Integer>> myMap;
3
Cyrille Ka

それらが2つの整数である場合は、キーをMap<String, ?>として使用して、i+"#"+jという手早く汚れたトリックを試すことができます。

キーi+"#"+jj+"#"+iと同じ場合は、min(i,j)+"#"+max(i,j)を試してください。

2
arutaku

次のような複合キーを表す値クラスを作成します。

class Index2D {
  int first, second;

  // overrides equals and hashCode properly here
}

equals()およびhashCode()を正しくオーバーライドするように注意してください。これが多くの作業のように思える場合は、Apache commonsが提供するPairなどの既製の汎用コンテナーを検討することができます。

ここには多くの 類似した質問 がありますが、Guavaの Table を使用するなど、他のアイデアもありますが、キーは異なるタイプを持つことができます。あなたのキーは両方とも整数であると理解しているので、あなたの場合は複雑です)。

1
BeeOnRope

次のようなキーオブジェクトを作成できます。

パブリッククラスMapKey {

public  Object key1;
public Object key2;

public Object getKey1() {
    return key1;
}

public void setKey1(Object key1) {
    this.key1 = key1;
}

public Object getKey2() {
    return key2;
}

public void setKey2(Object key2) {
    this.key2 = key2;
}

public boolean equals(Object keyObject){

    if(keyObject==null)
        return false;

    if (keyObject.getClass()!= MapKey.class)
        return false;

    MapKey key = (MapKey)keyObject;

    if(key.key1!=null && this.key1==null)
        return false;

    if(key.key2 !=null && this.key2==null)
        return false;

    if(this.key1==null && key.key1 !=null)
        return false;

    if(this.key2==null && key.key2 !=null)
        return false;

    if(this.key1==null && key.key1==null && this.key2 !=null && key.key2 !=null)
        return this.key2.equals(key.key2);

    if(this.key2==null && key.key2==null && this.key1 !=null && key.key1 !=null)
        return this.key1.equals(key.key1);

    return (this.key1.equals(key.key1) && this.key2.equals(key2));
}

public int hashCode(){
    int key1HashCode=key1.hashCode();
    int key2HashCode=key2.hashCode();
    return key1HashCode >> 3 + key2HashCode << 5;
}

}

これの利点は次のとおりです。すべてのシナリオのEqualsを常にカバーしていることを常に確認します。

NOTE:key1とkey2は不変でなければなりません。そうして初めて、安定したキーオブジェクトを構築できます。

1
Andy

複数のキーまたは値を渡すクラスを作成し、このクラスのオブジェクトをマップのパラメーターとして使用できます。

import Java.io.BufferedReader; 
import Java.io.FileReader;
import Java.io.IOException;
import Java.util.*;

 public class key1 {
    String b;
    String a;
    key1(String a,String b)
    {
        this.a=a;
        this.b=b;
    }
  }

public class read2 {

private static final String FILENAME = "E:/studies/Java/ReadFile_Project/nn.txt";

public static void main(String[] args) {

    BufferedReader br = null;
    FileReader fr = null;
    Map<key1,String> map=new HashMap<key1,String>();
    try {

        fr = new FileReader(FILENAME);
        br = new BufferedReader(fr);

        String sCurrentLine;

        br = new BufferedReader(new FileReader(FILENAME));

        while ((sCurrentLine = br.readLine()) != null) {
            String[] s1 = sCurrentLine.split(",");
            key1 k1 = new key1(s1[0],s1[2]);
            map.put(k1,s1[2]);
        }
        for(Map.Entry<key1,String> m:map.entrySet()){  
            key1 key = m.getKey();
            String s3 = m.getValue();
               System.out.println(key.a+","+key.b+" : "+s3);  
              }  
  //            }   
        } catch (IOException e) {

        e.printStackTrace();

    } finally {

        try {

            if (br != null)
                br.close();

            if (fr != null)
                fr.close();

        } catch (IOException ex) {

            ex.printStackTrace();

        }

    }

    }

 }
1
Vikas Pal

PairのキーとしてHashMapを使用します。 JDKにはペアはありませんが、 http://commons.Apache.org/lang などのサードパーティ製ライブラリを使用するか、独自のペアのタイプを記述できます。

0
MrSmith42

以下のリンクからダウンロードできます。 https://github.com/VVS279/DoubleKeyHashMap/blob/master/src/com/virtualMark/doubleKeyHashMap/DoubleKeyHashMap.Java

https://github.com/VVS279/DoubleKeyHashMap

ダブルキーを使用できます:値ハッシュマップ、

   DoubleKeyHashMap<Integer, Integer, String> doubleKeyHashMap1 = new 
   DoubleKeyHashMap<Integer, Integer, String>();

   DoubleKeyHashMap<String, String, String> doubleKeyHashMap2 = new 
   DoubleKeyHashMap<String, String, String>();
0
VISHAL SINGH

このためにguava Table実装を使用することもできます。

テーブルは、2つのキーを組み合わせて指定して単一の値を参照できる特別なマップを表します。これは、マップのマップを作成することに似ています。

//create a table
  Table<String, String, String> employeeTable = HashBasedTable.create();

  //initialize the table with employee details
  employeeTable.put("IBM", "101","Mahesh");
  employeeTable.put("IBM", "102","Ramesh");
  employeeTable.put("IBM", "103","Suresh");

  employeeTable.put("Microsoft", "111","Sohan");
  employeeTable.put("Microsoft", "112","Mohan");
  employeeTable.put("Microsoft", "113","Rohan");

  employeeTable.put("TCS", "121","Ram");
  employeeTable.put("TCS", "122","Shyam");
  employeeTable.put("TCS", "123","Sunil");

  //get Map corresponding to IBM
  Map<String,String> ibmEmployees =  employeeTable.row("IBM");
0
slisnychyi