[英]How to create a HashMap with two keys (Key-Pair, Value)?
我有一個二維整數數組。 我希望將它們放入 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;
}
實際上是您可以做的最糟糕的實現之一。 原因很簡單:你有很多相等的哈希值! 並且hashCode()
應該返回往往很少見的 int 值,最好是唯一的。 使用這樣的東西:
public int hashCode() {
return (X << 16) + Y;
}
這速度很快,並為 -2^16 和 2^16-1(-65536 到 65535)之間的鍵返回唯一的哈希值。 這幾乎適用於任何情況。 很少你會超出這個界限。
第三,在實現equals()
時,還要知道它的用途並了解如何創建密鑰,因為它們是對象。 通常你會做不必要的 if 語句,因為你總是會得到相同的結果。
如果您創建這樣的鍵: map.put(new Key(x,y),V);
你永遠不會比較你的鑰匙的參考。 因為每次你想訪問地圖時,你都會做類似map.get(new Key(x,y));
. 因此,您的equals()
不需要像if (this == obj)
的語句。 它永遠不會發生。
而不是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
提供公共訪問級別,因為它們是最終的並且不包含敏感信息。 在將Object
轉換為Key
時,我不能 100% 確定private
訪問級別在任何情況下是否都能正常工作。
如果你想知道決賽,我將任何東西聲明為 final,它的值是在實例化時設置的並且永遠不會改變 - 因此是一個對象常量。
您不能擁有一個包含多個鍵的哈希映射,但您可以擁有一個以多個參數作為鍵的對象。
創建一個名為 Index 的對象,該對象采用 x 和 y 值。
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>
得到你的結果。 :)
在通用集合MultiKeyMap中實現
兩種可能。 要么使用組合鍵:
class MyKey {
int firstIndex;
int secondIndex;
// important: override hashCode() and equals()
}
或地圖地圖:
Map<Integer, Map<Integer, Integer>> myMap;
使用Pair
作為HashMap
的鍵。 JDK 沒有 Pair,但您可以使用 3rd 方庫,例如http://commons.apache.org/lang或編寫自己的 Pair taype。
Java 7+ 包含一個新的Map.Entry<K,V>
類,您可以將其用作地圖的鍵(或集合的條目)。 Java 9+ 還包含一個Map.entry(K k, V v)
方法來輕松創建新的Map.Entry
對象。
用法:
Map<Map.Entry<Integer,Integer>, Integer> map = new HashMap<>();
map.put(Map.entry(1, 2), 0);
javafx.util 中還有Pair<K, V>
Map<Pair<Integer,Integer>, Integer> map = new HashMap<>();
map.put(new Pair(1, 2), 0);
如果它們是兩個整數,您可以嘗試一個快速而骯臟的技巧: Map<String, ?>
使用鍵作為i+"#"+j
。
如果鍵i+"#"+j
與j+"#"+i
相同,請嘗試min(i,j)+"#"+max(i,j)
。
你可以像這樣創建你的關鍵對象:
公共類 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 的所有場景。
注意:您的 key1 和 key2 應該是不可變的。 只有這樣你才能構造一個穩定的關鍵對象。
您也可以為此使用guava Table實現。
表表示一個特殊的映射,其中可以以組合方式指定兩個鍵來引用單個值。 它類似於創建地圖的地圖。
//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");
我們可以創建一個類來傳遞多個鍵或值,並且該類的對象可以用作映射中的參數。
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();
}
}
}
}
您可以從以下鏈接下載它: 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>();
使用 org.apache.commons.lang3.tuple.Pair 非常簡單;
Map<String, Pair<String, Integer>> map= new HashMap<>();
map.put("key", Pair.of("a", 1));
int value = map.get("key").getRight();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.