在ArrayList中存储2d数组位置

时间:2016-04-16 06:58:32

标签: java arrays

我想在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[][]成立?

2 个答案:

答案 0 :(得分:1)

您正在寻找的解决方案

在聊天中与你交谈后,我们确定你正在制作数独游戏,并且你想存储动作,并且能够撤消这些动作。

您将电路板存储为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;
}

我们将sudokuGrid传递给undoMove非常重要。否则,undoMove将无法对游戏板进行永久性更改。您可以阅读我在下面提供的链接,了解有关您可以对sudokuGrid进行更改的原因的详细信息。

现在,我们需要关注如何存储动作。

存储移动

我们有几个选项,但我认为最简单的方法是创建一个ArrayList并将Move存储在其中。当然,Java还没有为我们定义Move。我们必须创建自己的类来定义Move

如果您不熟悉课程,可以学习基础知识herehere

这是我们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&#39;

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&#39}的数组,请执行以下操作:

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

然后playedValues将存储Integerint&#39}的数组。

您可以像这样使用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]
        );
    }
}

还有更好的方法!

如果您像使用2D阵列一样使用ArrayList,但仍然需要ArrayList的所有灵活性和功能,那么请执行以下操作:

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

将playbackValues设置为ArrayList,其中包含保存int的ArrayLists。与使用int[][]非常相似,int使用包含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) ); } } s&#39;的数组的数组。

上面的代码可以使用这个新的ArrayList的ArrayList来实现,如下所示:

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) );
}

如果您想存储,可能是9x9网格,您可以轻松地这样做:

2d array

但是,你应该使用ArrayList吗?

我在这里看不到使用ArrayList的巨大 需要 。当我看到你的代码并阅读你想要做的事情时,我立即想到// 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] ); } }

您的代码或我的答案中没有任何内容可以通过二维数组完成。它可能会使事情变得更简单。唯一的问题是,如果您需要动态添加数组。 2d数组不能这样做。

这是与上面相同的实现,带有2d数组:

setCell

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

setCell

修复int方法

如果我们有一个存储// 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; } 的数组的ArrayList,我们可以使用此实现更改某个单元格:

gridIndex

原始错误

问题不在cell,与NullPointerException有关。

您可以从int获得int,因为所有setCell在Java中的默认/空值均为0。 请参阅文档 hereherehere this post's answers ,以获取相关证明。

问题不在于cell方法,而在于cell变量。由于nullsetCell,因此抛出 NullPointerException ,而不是您传递给setCell的任何内容。

为什么setCell最初没有工作

正如其他答案所指出的那样,方法setCell实际上并没有做任何明显的事情。这是因为Java 按值传递,而不是按引用传递。您可以阅读this post了解详细说明。

这背后的意思是,无论您将valuegridIndex传递给setCell的实际数字值,int gridIndex = 10, myValue = 2; setCell(myValue, gridIndex); 都会有 ,但 引用

此代码:

setCell

将致电gridIndex并传递myValuesetCell ,分别为10和2. {{ 1}}方法从不看到实际变量gridIndexmyValuesetCell没有引用这些变量,它只看到 10和2.

这可能令人困惑,因为值存储在setCell内的变量中,您指定的变量是参数名称(int value,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。

答案 1 :(得分:-1)

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的值,也不编辑任何变量。它什么都不做,因为它改变的唯一值是在其签名中声明的值,并且当方法退出时会丢失。