簡體   English   中英

將二維數組位置存儲在ArrayList中

[英]Store 2d array positions in ArrayList

我想在ArrayList中存儲幾個2d數組位置,並按如下所示進行設置:

ArrayList<Integer> playedValues = new ArrayList<Integer>();
playedValues.add(dataArray[0][1]);
playedValues.add(dataArray[0][2]); //example of adding 2d array positions

int size = playedValues.size(); //get size of ArrayList
int gridIndex = playedValues.get(size - 1); //trying to set gridIndex to dataArray[0][2]

cell.setCell(0, gridIndex); //this is where the error occurs

//trying to pass gridIndex to here
public void setCell(int value, int gridIndex) {
    gridIndex = value;
}

我的問題是,當我嘗試將gridIndex作為參數傳遞給setCell ,得到了NullPointerException

我將其傳遞給的方法在我的測試中似乎可以正常工作,因此我認為gridIndex is not being set properly 如何使playedValues本身存儲dataArray[][]而不是dataArray[][]持有的信息?

您正在尋找的解決方案

在與您聊天后,我們確定您正在制作Sudoku游戲,並且您想要存儲移動並能夠撤消這些移動。

您將板存儲為sudokuGrid ,它是一個2d int數組。 您需要能夠對某些單元格(行,列)進行更改。 您還需要能夠存儲移動(行,列)和順序。 然后,您可以同時使用這兩個功能,並允許用戶撤消其移動。

讓我們專注於首先更改單元格。

撤消動作

我們可以編寫一個方法,該方法接受一行和一列,然后將(行,列)單元格的值改回0。(撤消移動)。

我們應該可以像這樣調用此方法:

int testRow = 4, testColumn = 1;
undoMove(testRow, testColumn, sudokuGrid);

當然,稍后我們將使用先前動作中的行和列,但是我們現在需要能夠進行測試。 undoMove方法的編寫方式如下:

public void undoMove(int row, int column, int[][] board) {
    board[row][column] = 0;
}

這是非常重要的,我們在傳遞sudokuGridundoMove 否則, undoMove將無法對游戲板進行永久更改。 您可以閱讀下面我提供的鏈接,以獲取有關為何能夠對sudokuGrid進行更改的更多信息。

現在,我們需要集中精力存儲動作。

儲存動作

我們有一些可用的選項,但是我認為最簡單的方法是創建一個ArrayList並將其中的Move存儲在其中。 當然,Java尚未為我們定義Move 我們將必須創建自己的類來定義Move

如果您不熟悉制作課程,可以這里學習基礎知識。

這是我們的Move類的樣子:

class Move {
    int row, column;

    public Move(int row, int column) {
        this.row = row;
        this.column = column;
    }
}

public void undoMove(int row, int column, int[][] board) {
    board[row][column] = 0;
}

這只是說每個Move將有一行,一列。 現在,我們可以存儲每個動作在其中的單元格的行和列。

現在,我們可以創建一個ArrayList來保存Move

ArrayList<Move> moves = new ArrayList<Move>();

每次用戶移動時,我們都可以創建一個Move對象,如下所示:

// You'll need to get the row and column 
// before you make the Move object
Move currentMove = new Move(row, column);

現在,只要我們想撤消任何動作,我們都可以簡單地做到這一點:

Move moveToUndo = moves.get( moves.size() - 1 );
undoMove(moveToUndo.row, moveToUndo.column, sudokuGrid);
moves.remove( moves.size() - 1 );

現在在一起!

class Move {
    int row, column;

    public Move(int row, int column) {
        this.row = row;
        this.column = column;
    }
}

public void undoMove(int row, int column, int[][] board) {
    board[row][column] = 0;
}

// Later on, in your game loop method
ArrayList<Move> moves = new ArrayList<Move>();

// Adding moves
// In your program, you'll get the row and column from what
// the user types in or clicks on. 
int row = 1, column = 7;
moves.add( new Move(row, column) );

row = 6, column = 8;
moves.add( new Move(row, column) );

// Undo'ing moves
Move moveToUndo = moves.get( moves.size() - 1 );
undoMove(moveToUndo.row, moveToUndo.column, sudokuGrid);
moves.remove( moves.size() - 1 );

您甚至可以重寫undoMove方法以接受Move ,而不是一行和一列,這看起來非常干凈。 您也可以編寫一個方法undoLastMove ,該方法可以自動完成某些過程。


解決您的ArrayList問題

我不太確定您打算將ArrayList playedValues用途,因此我不得不做出一些有根據的猜測,即您想讓ArrayList保存數組,而不是單個值。

那很簡單!

您當前的聲明:

ArrayList<Integer> playedValues = ArrayList<Integer>();

設置playedValues以容納Integerint值。 要改為設置playedValues以容納int的數組,請執行以下操作:

ArrayList<Integer[]> playedValues = ArrayList<Integer[]>();

然后playedValues將存儲Integerint的數組。

您可以像這樣使用ArrayList:

ArrayList<Integer[]> playedValues = ArrayList<Integer[]>();

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

// Adding arrays to the list
playedValues.add(arrayOne);

// Iterating through all arrays in playedValues
for(int i = 0; i < playedValues.size(); i++) {
    int[] currentArray = playedValues.get(i);

    // Then, of course, you can loop over each array like normal:
    for(int j = 0; j < currentArray.length; j++) {
        System.out.println(
            "Array #" + i + " - Element #" + j + " = " + currentArray[i][j]
        );
    }
}

有更好的方法!

如果您使用ArrayList的方式與使用2D數組的方式相同,但是您仍然想要ArrayList的所有靈活性和功能,請執行以下操作:

ArrayList<ArrayList<Integer>> playedValues = ArrayList<ArrayList<Integer>>();

那將playedValues設置為一個ArrayList,其中保存了包含int的ArrayList。 與使用int[][]非常相似,后者使用一個數組來保存持有int s'的數組。

可以使用新的ArrayLists ArrayList來實現上述代碼,如下所示:

ArrayList<ArrayList<Integer>> playedValues = ArrayList<ArrayList<Integer>>();

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

// Adding values to the playedValues
playedValues.add( Arrays.asList(arrayOne) );

// Iterating through all values in playedValues
for(int i = 0; i < playedValues.size(); i++) {
    for(int j = 0; j < playedValues.get(i).size(); j++) {
        System.out.println(
            "Row #" + i + " - Column #" + j + " = " + playedValues.get(i).get(j)
        );
    }
}

如果您想存儲(可能是9x9的網格),則可以像這樣輕松地進行操作:

ArrayList<ArrayList<Integer>> playedValues = ArrayList<ArrayList<Integer>>();
int[] sampleRow = {0, 0, 0, 0, 0, 0, 0, 0, 0};

for(int i = 0; i < 9; i++) {
    playedValues.add( Arrays.asList(sampleRow) );
}

但是,您應該使用ArrayList嗎?

我認為這里不需要使用ArrayList。 當我看到您擁有的代碼並閱讀您要執行的操作時,我立即想到2d array

在您的代碼或我的答案中,沒有任何事情是二維數組無法完成的。 這也可能使事情變得更簡單。 唯一的問題是,是否需要動態添加陣列。 2d數組無法做到這一點。

這是與上述相同的實現,帶有2d數組:

// 100 for rows and columns was chosen arbitrarily.
int[][] playedValues = new int[100][100];

int[] arrayOne = {1, 2, 3, 4, 5};
int[] arrayTwo = {1337, 9001, 1111111, 22222, 33333, 444, -1, -123, 246};

// Adding arrays to the list
playedValues[0] = arrayOne;
playedValues[1] = arrayTwo;

// Iterating through all arrays in playedValues
for(int i = 0; i < playedValues.length; i++) {
    for(int j = 0; j < playedValues[i].length; j++) {
        System.out.println(
            "Array #" + i + " - Element #" + j + " = " + currentArray[i][j]
        );
    }
}

setCell方法:

public void setCell(int value, int row, int column, int[][] grid) {
    grid[row][column] = value;
}

修復setCell方法

如果我們有一個存儲int數組的ArrayList,則可以使用此實現更改某個單元格:

// Making a call to set the cell in the 1st row at the 4th column, to 0
setCell(0, 1, 4, playedValues);

public void setCell(int value, int row, int column, ArrayList<Integer[]> grid) {
    int[] rowArray = grid.get(row);
    rowArray[column] = value;
}

原始錯誤

問題不gridIndex ,而是cell

您可以從int獲取NullPointerException ,因為在Java中所有int的默認/空值均為0。 有關證明請參見 此處此處此處 的文檔 以及 本文的答案

所以問題不在於setCell方法,而是與您的cell變量有關。 由於cellnull而不是傳遞給setCell任何東西,因此引發NullPointerException


為什么setCell最初不起作用

正如其他答案所指出的,確實是setCell方法實際上不會做任何明顯的事情。 這是因為Java是按值傳遞的 ,而不是按引用傳遞的 您可以閱讀這篇文章以獲取詳細說明。

這在幕后的意思是,無論您傳遞給setCell作為valuegridIndex任何實際數字值, setCell都將具有的 ,但沒有引用

這段代碼:

int gridIndex = 10, myValue = 2;
setCell(myValue, gridIndex);

將調用setCell並傳遞gridIndexmyValue (分別為10和2) setCell方法從不看到實際變量gridIndexmyValuesetCell沒有引用這些變量,它僅看到 10和2。


這可能會造成混淆,因為值存儲在setCell內的變量中, setCell是您指定為參數名稱的變量(int值,int gridIndex),但這些變量不是傳遞給setCell的變量。 參見以下代碼:

public static void main(String[] args) {
    int gridIndex = 10, myValue = 9999;
    setCell(myValue, gridIndex);
    System.out.println(gridIndex);
}

public static void setCell(int value, int gridIndex) {
    // In here, value is NOT the same variable, myValue, that
    // we passed in. Just the same, gridIndex, is not the same 
    // variable that we passed in from main.

    // In here, value and gridIndex have the SAME VALUES
    // as the variables we pass in, but they are not the same
    // variables. They are newly made variables, with the same values.
}

還要看下面的代碼:

public static void main(String[] args) {
    setCell(10, 9999);
    System.out.println(gridIndex);
}

public static void setCell(int value, int gridIndex) {
    gridIndex = value;
}

我們沒有將變量傳遞給setCell ,但是在setCell內部,我們將變量gridIndex更改為等於value 這會告訴Java,數字9999的新值實際上應該是10嗎? 當然不是。 我們沒有更改傳入的內容,而是更改了保存傳入值的變量。


考慮發生情況的一種簡單方法是記住,每當在Java中使用int變量時,都可以將變量名替換為其持有的值,並且代碼將保持完全相同。

以下面的代碼為例:

int gridIndex = 10, myValue = 9999;
setCell(myValue, gridIndex);

等效代碼為:

setCell(10, 9999);

正如我們在上面看到的,我們當然不能更改10或9999的值。我們不能僅僅確定數字等於其他數字。 當然,我們可以更改int中保存的數字,但是沒有任何int變量傳遞給setCell ,只有數字值(如10或9999)。

public void setCell(int value, int gridIndex) {
  gridIndex = value;
}

上面的代碼什么都不做。 它需要兩個參數,並將其中一個參數本地設置為另一個。 然后,由於兩個變量都在函數中聲明,因此退出時它們都消失了。

由於此方法僅設置gridIndex,為什么不直接設置它呢?

gridIndex = 0;

編輯:為什么這不起作用的示例。

我在IDE中進行了嘗試-它與您擁有的setCell方法完全相同。

public static void main(String[] args) {
    int gridIndex = 10;
    setCell(0, gridIndex);
    System.out.println(gridIndex);
}

public static void setCell(int value, int gridIndex) {
    gridIndex = value;
}

控制台顯示10,因為setCell不執行任何操作。 它不設置gridIndex的值,也不編輯任何變量。 它什么也不做,因為它更改的唯一值是在其簽名中聲明的值,並且在方法退出時丟失。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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