簡體   English   中英

如何創建具有兩個鍵(鍵對、值)的 HashMap?

[英]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的另一種方式。

數組索引ij可以通過以下方式表示為單個key

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

並且可以通過這種方式從key中檢索索引:

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

有幾種選擇:

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類)。

當您創建自己的密鑰對對象時,您應該面對一些事情。

首先,您應該知道實現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;
  }

}

您可以為維度索引XY提供公共訪問級別,因為它們是最終的並且不包含敏感信息。 在將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);

創建一個代表復合鍵的值類,例如:

class Index2D {
  int first, second;

  // overrides equals and hashCode properly here
}

注意正確覆蓋equals()hashCode() 如果這看起來工作量很大,您可能會考慮一些現成的通用容器,例如 apache commons 提供的Pair等。

這里也有許多類似的問題,還有其他想法,例如使用 Guava's Table ,盡管允許鍵具有不同的類型,在您的情況下這可能是過度的(在內存使用和復雜性方面),因為我知道您的鍵都是整數。

如果它們是兩個整數,您可以嘗試一個快速而骯臟的技巧: Map<String, ?>使用鍵作為i+"#"+j

如果鍵i+"#"+jj+"#"+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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM