2015-10-20 96 views
1

答案: 感謝您的幫助!和大多數人一樣,解決方案是創建一個新的2d int數組,然後複製舊數組中的值。這是我所做的功能,然後我可以將新板添加到散列表中,作爲一個新的密鑰。將新密鑰放入HashMap替換現有的不同密鑰

void newboard(){ 
    NewBoard = new int[N][N]; 
    for(int n = 0; n < N; n++){ 
     for(int i = 0; i < N; i++){ 
      NewBoard[n][i] = CurrentBoard[n][i]; 
     } 
    } 
} 

的問題:

我有下面的代碼,即把一個3×3的板與一個整數列表,具體地(F,G,H)到一個HashMap沿。董事會CurrentBoard是一個未解決的8難題。

public static HashMap<int[][], List<Integer>> map = new HashMap<>(); 
map.put(CurrentBoard, fgh); 

我初始化了散列圖,對於剩餘的程序我想遍歷地圖來獲取我需要的板。在'0'位置被移動後,地圖的每個條目都將是8拼圖板的特定狀態。

這是我的做法。 'cv'變量只是選擇具有最低「f」值的電路板(鍵)。

for(Map.Entry<int[][], List<Integer>> mapentry : map.entrySet()) { 
     if (cv > mapentry.getValue().get(0)) { 
      cv = mapentry.getValue().get(0); 
      CurrentBoard = mapentry.getKey(); 
      fgh = mapentry.getValue(); 
     } 
} 

現在,我已經在「CurrentBoard」變量得到了一局,我想移動「0」一行。所以,我調用此函數:

void moveUp(){ 
    NewBoard = CurrentBoard; 
    memory = NewBoard[ZeroPositionX][ZeroPositionY - 1]; 
    NewBoard[ZeroPositionY- 1][ZeroPositionX] = 0; 
    NewBoard[ZeroPositionY][ZeroPositionX] = memory; 
} 

然後我做了幾個(這個問題)不重要的檢查,並重新計算fgh值這個NewBoard

然後我繼續使用

map.put(NewBoard, fgh); 

我的問題放在與fgh值到hashmap沿NewBoard是,這個替換HashMap中的當前密鑰。換句話說,不是向hashmap添加鍵和值,而是替換已經存在的鍵和值。我已經嘗試打印新紙板和當前紙板,以確保它們不同。

當我打印 hashmap它只給我最新的條目。換句話說,董事會以及移動'0'後的數值。

for(Map.Entry mapentry : map.entrySet()){ 
     System.out.println(mapentry); 
    } 

爲什麼添加新鍵和價值hashmap不行?

Endnote:我是Java新手,所以其中一些可能不是最優的。如有必要,我會盡力詳細解釋。

+0

看起來像你並不真的創建一個新的數組,但改變現有數組中的一些值。然而,這很難說。還要注意''int [] []'既不會覆蓋equals或'hashCode',這意味着如果您使用的鍵不在地圖中(同一個實例),您將無法找到該值。 – fabian

+0

你需要克隆你的電路板, –

+2

除了@ fabian的評論之外,在類中包裝'int [] []'並重寫'hashCode'以使用類似'java.util.Arrays.deepHashCode( yourArray)'。對於equals,你可以使用:'java.util.Arrays.deepEquals(thisArray,thatArray)' –

回答

0

您正在更改NewBoard變量/數組的內容,但引用保持不變。所以當你撥打map.put(NewBoard, fgh);時,關鍵是始終是相同的參考(認爲內存中的地址相同,但每次都有不同的內容)。

如果您想在地圖上爲每個紙板狀態存儲新條目,則必須每次創建一個新數組並複製+更改其內容。

+0

這確實是個問題。通過創建一個新的數組,只需將CurrentBoard中的值複製到新的數組中即可。 (而不是簡單地設置「NewBoard = CurrentBoard」) 正如你所說的,我只是總是「指向」我的密鑰,並對該密鑰進行更改,而不僅僅是將密鑰放入的變量。 –

0

問題是,您正在修改int[][]這是您的HashMap密鑰,而不是創建一個新的。這裏是你的代碼的總結(有些線路剪斷):

CurrentBoard = mapEntry.getKey(); //here CurrentBoard points at the exact same object as the key in your map 
NewBoard = CurrentBoard; //now NewBoard and CurrentBoard are both pointing at the same int[][] 
NewBoard[a][b] = 0; //this updates that one object 
NewBoard[c][d] = memory; //still updating the same object 
map.put(NewBoard, fgh); //NewBoard is still the same object, so this is replacing the existing key 

需要注意的是,在一般情況下,在地圖修改任何主要的內容是不是一個好主意 - 它可能會導致更奇怪的行爲比你看到了。

另外,在使用數組作爲地圖鍵通常是錯的 - 因爲地圖取決於key1.equals(密鑰)的結果,以及任何Java數組a1, a2a1.equals(a2)只有a1 == a2(也就是說,他們」重新相同的數組)。例如:

int[] a1 = new int[1]; 
a1[0] = 1; 
int[] a2 = new int[1]; 
a2[0] = 1; 
System.out.println(a1.equals(a2)); //prints "false" 
+0

correct.you應該創建一個新的板,因爲你不能覆蓋int [] []的equals和hashcode。 –

0

問題是您正在修改相同的密鑰,這不會按預期工作。爲了獲得「正確」的行爲,你應該克隆你的密鑰。由於您的密鑰是int[][],您不需要任何操作,只需撥打clone()即可。

int[][] currentBoard = {{1, 2, 3}, {4, 5, 6}}; 

    HashMap<int[][], String> map = new HashMap<int[][], String>(); 

    map.put(currentBoard, "test1"); 

    int[][] cloned = currentBoard.clone(); 

    cloned[0][0] = 10; 

    map.put(cloned, "test2"); 

    for(Map.Entry mapentry : map.entrySet()){ 
     System.out.println(mapentry.getValue()); 
    } 

打印

test1 
test2 

如果你想使用你已經創建了一些類,你需要重寫clone(),看到Cloneable

需要注意的是克隆()將只克隆數組引用,而不是數值。所以currentBoard[0].equals(cloned[0])將是真實的,但我認爲這對你的情況沒有任何影響。

也看到了這個問題的SO有關克隆Java: recommended solution for deep cloning/copying an instance

+0

克隆二維數組無助於您,需要進行深度複製。 –

+0

@LouisWasserman謝謝,但我認爲這取決於OP的情況,我不確定是否沒有深層複製將解決問題,因此我將這個'重要提示...' –

0

int[][]類型的地圖鍵不會改變其equalshashCode方法的行爲改變的值。這些是被調用來確定的方法,密鑰在語義上是否相同。

因此,要添加新密鑰,您必須創建一個新密鑰或使用不同的equals/hashCode邏輯的適當類。

要創建一個新的密鑰,你可以使用clone()

void moveUp() { 
    NewBoard = new int[3][3]; 
    NewBoard[0] = CurrentBoard[0].clone(); 
    NewBoard[1] = CurrentBoard[1].clone(); 
    NewBoard[2] = CurrentBoard[1].clone(); 
    memory = NewBoard[ZeroPositionX][ZeroPositionY - 1]; 
    NewBoard[ZeroPositionY- 1][ZeroPositionX] = 0; 
    NewBoard[ZeroPositionY][ZeroPositionX] = memory; 
} 

注意,我們必須調用clone三次,因爲它不能夠完全克隆一個兩維數組(見here)。

一個更清潔的方式是創建一個Board類像這樣(未經測試,請原諒錯別字):

public class Board { 

    private int[][] content = new int[3][3]; 

    /** 
    * Creates a new empty board. 
    */ 
    public Board() { 
    } 

    /** 
    * Call this constructor to create a new instance of a given board. 
    */ 
    public Board(Board otherBoard) { 
     this.content[0] = otherBoard.content[0].clone() 
     this.content[1] = otherBoard.content[1].clone() 
     this.content[2] = otherBoard.content[2].clone() 
    } 

    public void set(int a, int b, int value) { 
     content[a][b] = value; 
    } 

    public int get(int a, int b) { 
     return content[a][b]; 
    } 

    public int hashCode() { 
     int code = 0; 
     for (int a=0; a<3; a++) { 
      for (int b=0; b<3; b++) { 
       code += content[a][b]; 
      } 
     } 
     return code; 
    } 

    public boolean equals(Object that) { 
     if (!(that instanceof Board)) return false; 
     return Arrays.equals(this.content[0], that.content[0]) 
      && Arrays.equals(this.content[1], that.content[1]) 
      && Arrays.equals(this.content[2], that.content[2]) 
    } 
} 

總體而言,你應該學習的Map一般合同https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

而且,你的代碼,請確保你從來沒有更改密鑰的內容,一旦它用在Map。否則混亂將統治...

祝你好運。