整数の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;
いくつかのオプションがあります:
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
は、マップのマップを使用します。
特別なKey
クラスがn次元にスケーリングする唯一のアプローチであることに注意してください。次のことも検討してください。
Map<List<Integer>, V> map = //...
しかし、それはパフォーマンスの観点からもひどいし、読みやすさと正確さ(リストのサイズを強制する簡単な方法ではありません)。
タプルとcase
クラスが存在するScalaを見てください(Key
クラス全体をワンライナーに置き換えてください)。
独自のキーペアオブジェクトを作成する場合、いくつかのことに直面する必要があります。
まず、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
には、最終的なものであり、機密情報が含まれていないため、パブリックアクセスレベルを指定できます。 private
をObject
にキャストするときに、Key
アクセスレベルがanyの場合に正しく機能するかどうかは100%わかりません。
ファイナルについて疑問がある場合は、インスタンス化時に設定され、変更されない値をファイナルとして宣言します。したがって、オブジェクト定数です。
複数のキーを持つハッシュマップを作成することはできませんが、キーとして複数のパラメーターを取るオブジェクトを作成することはできます。
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>
を使用して結果を取得します。 :)
Common-collectionsで実装 MultiKeyMap
2つの可能性。組み合わせたキーを使用します:
class MyKey {
int firstIndex;
int secondIndex;
// important: override hashCode() and equals()
}
または地図の地図:
Map<Integer, Map<Integer, Integer>> myMap;
それらが2つの整数である場合は、キーをMap<String, ?>
として使用して、i+"#"+j
という手早く汚れたトリックを試すことができます。
キーi+"#"+j
がj+"#"+i
と同じ場合は、min(i,j)+"#"+max(i,j)
を試してください。
次のような複合キーを表す値クラスを作成します。
class Index2D {
int first, second;
// overrides equals and hashCode properly here
}
equals()
およびhashCode()
を正しくオーバーライドするように注意してください。これが多くの作業のように思える場合は、Apache commonsが提供するPair
などの既製の汎用コンテナーを検討することができます。
ここには多くの 類似した質問 がありますが、Guavaの Table を使用するなど、他のアイデアもありますが、キーは異なるタイプを持つことができます。あなたのキーは両方とも整数であると理解しているので、あなたの場合は複雑です)。
次のようなキーオブジェクトを作成できます。
パブリッククラス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は不変でなければなりません。そうして初めて、安定したキーオブジェクトを構築できます。
複数のキーまたは値を渡すクラスを作成し、このクラスのオブジェクトをマップのパラメーターとして使用できます。
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();
}
}
}
}
Pair
のキーとしてHashMap
を使用します。 JDKにはペアはありませんが、 http://commons.Apache.org/lang などのサードパーティ製ライブラリを使用するか、独自のペアのタイプを記述できます。
以下のリンクからダウンロードできます。 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>();
このために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");