【问题标题】:How can I manipulate 2D arrays in Java?如何在 Java 中操作二维数组?
【发布时间】:2014-12-05 15:41:16
【问题描述】:

我一直在为即将到来的 Java 考试而学习,但我很难将我的头脑围绕在 2D 数组上。我已经掌握了一些基础知识,例如创建和初始化一个二维数组,但是当涉及到插入、删除甚至排序时,我感到很困惑。我的教授花了 10 分钟来复习基础知识,但在我们的考试中,我们应该知道如何创建一个二维对象数组,并通过插入、删除和排序数组中的对象来操作数据。他让我们在考试中手写所有代码,因此不允许计算机协助完成这个过程。我已经花了几个小时在这里和其他网站上倾注示例,但我仍然觉得我对材料的理解不够好,无法亲手编写所有代码并正确处理。

我的困惑主要源于嵌套的for 循环通常用于在二维数组中移动。我可以看到其他人如何做到这一点并复制它,但我仍然不明白为什么循环会像他们那样工作。我敢肯定我在这里是少数,但无论出于何种原因,它背后的逻辑让我完全迷失了方向。

以我一直致力于帮助自己理解 2D 数组(以及其他考试材料)的这个(尽管很差)示例为例。假设您经营一家汽车经销商,并且您想订购汽车来填补您的库存。该程序以顶级abstract 类开始,该类描述了您一般销售的汽车(在我的例子中是奥迪)。经销商提供 4 种奥迪车型,A4A6A8R8。所有这些汽车(类)都从super 继承方法,命名为Audi。然后我想创建一个二维数组来存储库存的汽车。这将在我定义的另一个类中使用,包括search()delete()sort() 的方法。我们称之为AudiDealership。经销商每个模型只能持有 3 个,因此数组将类似于 Audi[4][3]。 A4 将填充第一行,subscript 0,A6 填充subscript 1,等等。我将如何设置for 循环以从正确的行中插入/删除?我显然不希望将 A4 插入应该容纳 A6 的行中,依此类推。

同样,我可以整天盯着代码并复制它,但我想理解 为什么/循环如何工作做。如果这个话题看起来微不足道或被殴打致死,我深表歉意,但我在发布之前所做的所有阅读都让我和以前一样困惑。这个网站上的许多人本身就是出色的老师,所以我想有人可以用我能理解的方式解释这一点。我的教授在这方面没有任何帮助,所以我正在使用外部手段来尝试解决问题。我非常感谢您提前提供的任何建议或解释:)

【问题讨论】:

标签: java for-loop multidimensional-array


【解决方案1】:

将二维数组视为包含其他数组的数组会有所帮助。例如Cars[0][5] 正在访问位于 0 的汽车数组,而实际汽车位于该数组的位置 5。 Cars[1][5] 将访问位置 1 处的第二个汽车数组,并且在位置 1 的数组的 5 处找到汽车。此代码可能会帮助您进一步理解它:

public class TwoDArray {

  public static void main(String[] args)
  {      
    Cars[][] cars; // declaring my 2D array.

    cars = new Cars[4][]; // making the x axis 4 cars wide.

    // now we will step along the x axis and create a Cars array in each slot.
    for ( int a = 0; a < cars.length; a++) // cars.length = how wide.
    { 
        cars[a] = new Cars[3]; // creating a new Cars[] in each slot of our 2D Car array @ position a.
                               //cars[a] = new 1D Cars array in slot a, length of 3.
    }

    // Note that we could have also created our array like this.
    // Cars[][] cars = new Cars[4][3];


    for ( int x = 0; x < cars.length; x++) //stepping along the x axis. cars.length = how wide.
    {   //every time we step thru x we will execute this next loop.
        for ( int y = 0; y < cars[x].length; y++) // stepping along the y axis. cars[x].length = how long.
        { // this loop will cycle through the y axis each time we increment x
            cars[x][y] = new Cars( 2014, "someAudi", x + " " + y ); // creating a new car(s) @ x,y position.
        }
    }

    // now to just print them.

    for ( int x = 0; x < cars.length; x++) //stepping along the x axis again.
    {
        for ( int y = 0; y < cars[x].length; y++) // stepping along the y axis.
        {
            System.out.println(cars[x][y].getYear() + 
                    " " + cars[x][y].getModel() +
                    " " + cars[x][y].getName() +
                    " " + cars[x][y].getManufacturer()); // the super method.
        }
    }

    //INSERTION. 

    // To insert into your array, you simply need to provide the coordinates to insert the new Car(s) object.
    // This next line will insert a new Car into the array at position 1 and the number 2 element of that array.
    cars[1][2] = new Cars( 2014, "someAudi", "My Favorite Car!");

    System.out.println(); // Just adding a space between outputs.

    for ( Cars[] c: cars) //extracting each Cars array and name it c from the 2D Cars array named cars.
    {                     //basically stepping along the x axis and getting each array stored in x.

        for ( Cars car: c) // Now we are stepping along the y axis.
        {                  // We are getting each individual Cars object and naming it car
                           // from each Cars[] named c from our first loop.

            System.out.println(car.getYear() + 
                    " " + car.getModel() +
                    " " + car.getName() +
                    " " + car.getManufacturer()); // the super method.
        }
    }

    // NOTE* if you wish to insert a new element and do not have extra capacity then you will need to
    // create a larger array @ cars[x]. cars[x] = new Cars[newSize];. 

    // DELETION.

    // To delete an element you can just simply overwrite it. 
    // such as:        
    cars[1][1] = new Cars( 2014, "someAudi", "new Audi"); // Essentially we deleted and inserted a new object
                                                          // at position [1][1]. 

    // If you just want to completely remove the element then you will need to update the size of the array.

    // You can define a new array to hold the values of the old array minus the element that should be deleted.
    Cars[] newArray = new Cars[cars[2].length - 1]; // We will use the array stored in cars[2] for this example.
                                                    // we set the length to one less to completely get rid of the
                                                    // old element.    

    int deleteThisPosition = 1; // We will use this variable to store the position that will be deleted from
                                // the array stored in cars[2].

    int newArrayPosition = 0; // We will use this to increment our position in the new array along with `a`
                              // in the next for loop.

    for ( int a = 0; a < cars[2].length; a++)
    {
        if ( a == deleteThisPosition) // if it reaches this position we will advance `a` and exclude it from
             a++;                     // our new array.

        newArray[newArrayPosition] = cars[2][a]; // we will store the value @ position `a` from the array in cars[2]
                                                 // into our newArray @ position `newArrayPosition`.                                     

        newArrayPosition++; // incrementing our variable to stay parallel with the array in cars[2]. 
    }

    //Now we can just assign the newArray to cars[2]. You will notice that Car `2 1` is no longer present.
    cars[2] = newArray;

    System.out.println(); // Just adding a space between outputs.

    for ( Cars[] c: cars) 
    {                                 
        for ( Cars car: c) 
        {                                 
            System.out.println(car.getYear() + 
                    " " + car.getModel() +
                    " " + car.getName() +
                    " " + car.getManufacturer()); // the super method.
        }
    }

  }
}

这是您示例中的其他类。

奥迪类:

public abstract class Audi { 

  public String getManufacturer() { return "Audi"; } // method from this super class.

}

汽车类:

public class Cars extends Audi{ //extending Audi.

  private String model;
  private String name;
  private int year;

  Cars(int year, String model, String name)
  {
    this.year = year;
    this.model = model;
    this.name = name;
  }

  public String getName() { return name; }    

  public String getModel() { return model; }

  public int getYear() { return year; }

}

如果您运行代码,您会注意到汽车名称中的模式。

输出:

注意每辆车名称中的模式,即唯一的列。它对应于我们如何逐步完成循环。我们从 x 开始,对于每个 x,我们遍历 y。 x + " " + y 是我们在上面的代码中命名每辆车的方式。

【讨论】:

  • 惊人的例子!这有助于我了解循环实际上是如何在数组中移动的。您的 cmets 使代码易于阅读,并且我知道它在每次迭代期间的运行方式。非常感谢 :) 为什么我的教授无法构建这样的东西,这超出了我的理解。
  • 很高兴能帮上忙。
  • 我更新了我的答案以包括插入和删除,以防您仍然需要一些帮助。还添加了增强的 for 循环,以防您也想了解这些循环。如果您愿意,可以忽略增强的循环,因为我只使用它们来打印数组。
  • 非常感谢!自从您发布此代码(在插入和删除之前)以来,我一直在玩一些代码,我想我已经开始掌握它了!加上你添加的其余部分,我会在周一的测试时间感觉更舒服。我非常感谢您的有用意见。像你这样的人有时让编程社区如此出色:)
  • 至于增强的 for 循环,我在常规数组中使用了 em 几次,我的教授上周在课堂上简要介绍了它们,但我从来没有真正了解它的要点,所以感谢您添加。我总是很想学习一些新东西,所以在提到增强循环时减少代码的便利是我应该更熟悉的。
【解决方案2】:

让我举个例子:

StringBuilder output = new StringBuilder();

    for (int i = 0; i < table.length; i++) {
        for (int j = 0; j < table[i].length; j++) {
            output.append(table[i][j]);
        }
        output.append("\n");
    }

这将是循环遍历二维数组的代码。

代码直接进入第一行。这是 i 值。 当您想遍历行的每一列时, 您需要知道行的长度才能循环遍历它。

所以你从第一行开始,一直走到最后,即 table[i].length。 在第一行中,第一个长度是 table[0].length。 这个长度是 3,因为每行有 3 列。

现在我们已经完成了第一行的循环,我们进入第二行。 通过进入第二行,我增加了 1。 所以我们的指针现在显示在第 2 行(table[i].length 中的 i 现在是 1,因为它总是从 0 开始)等等。

我们的指针遍历每一行,这就是它的工作原理。 每增加一行,i 的指针都会增加 1(即 for 循环中的 i++)。

随着每一行中的每一个新列,j 增加,而 i 保持不变。 i 仅在您输入新行时更改。 j 会随着输入一个新列而改变。

希望这会有所帮助;)

编辑:

另一个例子:

如果您想获取第 4 行中第 3 列的值:

你想要的值在这里:table[3][2]; 记住数组总是从 0 开始计数。:)

【讨论】:

  • 哇,视觉帮助了很多!无论出于何种原因,这对我来说是最困难的部分,可视化。随着你对每个部分的解释,我觉得我比以前理解了很多。我仍然不是 100%,但我可以使用一些代码并希望能弄明白。万分感谢! :)
  • 没问题:),我在启动时遇到了同样的问题。随意问:)
【解决方案3】:
Audi[4][3] cars = ... // your 2D array of all cars

正如您正确指定的,

A4 将填充第一行,下标 0,A6 填充下标 1,等等。

转换为cars[0] 持有Audi[] with A4 instancescars[1] 持有Audi[] with A6 instances 等等。

好的,所以

 Audi[] A4s = cars[0];
 Audi[] A6s = cars[1];
 ...

那你可以这么说

 Audi A4_1 = A4s[0];
 Audi A4_2 = A4s[1];
 Audi A4_3 = A4s[2];
 ...

并为您拥有的每辆车重复此操作。但这是错误的做法。首先,我们概括每辆车的访问权限。

如果您想遍历每个模型数组中的特定汽车,您需要一个带有索引的 for 循环,例如 specificCarIndex。循环遍历A4s 的数组会很简单:

 for (int specificCarIndex = 0; specificCarIndex < 3; specificCarIndex++) {
      // Here A4s[specificCarIndex] contains an object of concrete Audi car of model A4
  }

要遍历另一个模型(如 A6)的数组,您也可以这样做,将 A4s 替换为 A6s 等等。

现在我们需要概括一切。

  for (int carModelIndex = 0; carModelIndex < 4; carModelIndex++) {
      // Here cars[carModelIndex] holds an array of specific Audi model as you mentioned before
  }

cars[carModelIndex]本质上是Audi[] A4s如果carModelIndex == 0,那么Audi[] A6s如果carModelIndex == 1等等。

现在我们知道如何访问每个奥迪模型的数组,并且我们知道如何访问每个模型数组中的单个汽车,我们将两者结合起来:

 for (int carModelIndex = 0; carModelIndex < 4; carModelIndex++) {
     for (int specificCarIndex = 0; specificCarIndex < 3; specificCarIndex++) {
         // Here cars[carModelIndex][specificCarIndex] holds an object of type Audi which refers to a specific car
         // If double index seems difficult, consider this:
         // Audi[] audis = cars[carModelIndex] (array like A4s, A6s...)
         // Audi audi = audis[specificCarIndex] (specific car)
         // Just as in the examples before for-loops.
     }    
 }

【讨论】:

  • 感谢您与我的一个具体问题相关,即如何在阵列本身中搜索特定汽车。此外,您的变量名称帮助我了解循环的每个块与我的示例相关的作用。很难选择答案,因为你们都带来了一些有用的东西:)
猜你喜欢
  • 2015-06-21
  • 1970-01-01
  • 2019-07-29
  • 2015-07-12
  • 1970-01-01
  • 1970-01-01
  • 2018-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多