15.2 Multidimensional ArraysYou can think of arrays as long rows of slots into which values can be placed. Once you have a picture of a row of slots, imagine five rows, one on top of another. This is the classic two-dimensional array of rows and columns. The rows run across the array and the columns run up and down the array, as illustrated in Figure 15-1. Figure 15-1. Rows and columns create a multidimensional arrayA third dimension is possible but somewhat harder to picture. Imagine making your arrays three-dimensional, with new rows stacked atop the old two-dimensional array. OK, now imagine four dimensions. Now imagine ten. Those of you who are not string-theory physicists have probably given up, as have I. Multidimensional arrays are useful, however, even if you can't quite picture what they would look like. You might, for example, use a four-dimensional array to track movement in three dimensions (x,y,z) over time. C# supports two types of multidimensional arrays: rectangular and jagged. In a rectangular array, every row is the same length. In a jagged array, however, each row can be a different length. In fact, you can think of each row in a jagged array as an array unto itself. Thus, a jagged array is actually an array of arrays. 15.2.1 Rectangular ArraysA rectangular array is an array of two (or more) dimensions. In the classic two-dimensional array, the first dimension is the number of rows and the second dimension is the number of columns. To declare a two-dimensional array, use the following syntax: type [,] array-name For example, to declare and instantiate a two-dimensional rectangular array named myRectangularArray that contains two rows and three columns of integers, you would write: int [,] myRectangularArray = new int[2,3]; In Example 15-6, you create a two-dimensional array of integers and populate the array using two for loops. The outer for loop iterates once for each row, and the inner for loop iterates once for each column in each row: for (int i = 0;i < rows;i++) { for (int j = 0;j<columns;j++) { rectangularArray[i,j] = i+j; } } Then use a second set of for loops to display the contents of the array: for (int i = 0;i < rows;i++) { for (int j = 0;j<columns;j++) { Console.WriteLine("rectangularArray[{0},{1}] = {2}", i,j,rectangularArray[i,j]); } } The complete listing is shown in Example 15-6, followed by analysis. Example 15-6. Rectangular arrayusing System; namespace MultiDimensionalArrays { class Tester { public void Run() { const int rows = 4; const int columns = 3; // declare a 4x3 integer array int[,] rectangularArray = new int[rows, columns]; // populate the array for (int i = 0;i < rows;i++) { for (int j = 0;j<columns;j++) { rectangularArray[i,j] = i+j; } } // report the contents of the array for (int i = 0;i < rows;i++) { for (int j = 0;j<columns;j++) { Console.WriteLine("rectangularArray[{0},{1}] = {2}", i,j,rectangularArray[i,j]); } } } [STAThread] static void Main() { Tester t = new Tester(); t.Run(); } } } Output: rectangularArray[0,0] = 0 rectangularArray[0,1] = 1 rectangularArray[0,2] = 2 rectangularArray[1,0] = 1 rectangularArray[1,1] = 2 rectangularArray[1,2] = 3 rectangularArray[2,0] = 2 rectangularArray[2,1] = 3 rectangularArray[2,2] = 4 rectangularArray[3,0] = 3 rectangularArray[3,1] = 4 rectangularArray[3,2] = 5 In Example 15-6, you declare a pair of constant values to be used to specify the number of rows (4) and the number of columns (3) in the two-dimensional array: const int rows = 4; const int columns = 3; Creating these constants allows you to refer to the rows and columns by number throughout the program. If you decide later to change the value of either, you only have to make the change in one location in your code. You use the numeric values for the rows and columns to specify the dimensions of the array in the combined declaration and instantiation statement: int[,] rectangularArray = new int[rows, columns]; Notice the syntax. Everything up to and including the equal sign (=) is the declaration; everything following is the instantiation. The brackets in the int[,] declaration indicate that the type is an array of integers, and the single comma indicates the array has two dimensions; two commas would indicate three dimensions, and so on. The actual instantiation of rectangularArray: new int[rows, columns] sets the size of each dimension. Just as you can initialize a one-dimensional array using bracketed lists of values, you can initialize a two-dimensional array using a similar syntax. int[,] rectangularArray = { {0,1,2}, {3,4,5}, {6,7,8}, {9,10,11} }; The outer braces mark the entire array initialization, and the inner braces mark each of the elements in the second dimension. Since this is a 4x3 array (four rows by three columns), you have four sets of three initialized values (12 in all). Writing the initialization as: int[,]rectangularArray = { {0,1,2,3}, {4,5,6,7}, {8,9,10,11} }; would instead initialize a 3x4 array (three rows by four columns). Example 15-7 rewrites the Run() method from Example 15-6 to create and initialize a two-dimensional array. Example 15-7. Initializing a two-dimensional arraypublic void Run() { const int rows = 4; const int columns = 3; // define and initialize the array int[,] rectangularArray = { {0,1,2}, {3,4,5}, {6,7,8}, {9,10,11} }; // report the contents of the array for (int i = 0;i < rows;i++) { for (int j = 0;j<columns;j++) { Console.WriteLine("rectangularArray[{0},{1}] = {2}", i,j,rectangularArray[i,j]); } } } Output: rectangularArray[0,0] = 0 rectangularArray[0,1] = 1 rectangularArray[0,2] = 2 rectangularArray[1,0] = 3 rectangularArray[1,1] = 4 rectangularArray[1,2] = 5 rectangularArray[2,0] = 6 rectangularArray[2,1] = 7 rectangularArray[2,2] = 8 rectangularArray[3,0] = 9 rectangularArray[3,1] = 10 rectangularArray[3,2] = 11
As the output illustrates, the C# compiler understands the syntax of your initialization; the objects are accessed with the appropriate offsets. 15.2.2 Jagged ArraysA jagged array is an array of arrays. Specifically, a jagged array is a type of multi-dimensional array in which each row can be a different size from all the other rows. Thus, a graphical representation of the array has a "jagged" appearance, as in Figure 15-2. Figure 15-2. Jagged arrayYou can think of each row in a jagged array as a one-dimensional array unto itself. Thus, technically speaking, a jagged array is an array of arrays. When you create a jagged array, you declare the number of rows in your array. Each row holds a one-dimensional array, and each row can be of any length. To declare a jagged array, use the following syntax, where the number of brackets indicates the number of dimensions of the array: type [] []... For example, you would declare a two-dimensional jagged array of integers named myJaggedArray as follows: int [] [] myJaggedArray; Address the elements in the array as follows: the array name then the offset into the array of arrays (the row), and then the offset into the chosen array (the column within the chosen row). That is, to access the fifth element of the third array, write: myJaggedArray[2][4] Remember that all arrays are zero-based. The third element is at offset 2, and the fifth element is at offset 4. Example 15-8 creates a jagged array named myJaggedArray, initializes its elements, and then prints their content. To save space, the program takes advantage of the fact that integer array elements are automatically initialized to zero, and it initializes the values of only some of the elements.
Example 15-8. Jagged arrayusing System; namespace JaggedArray { class Tester { public void Run() { const int rows = 4; const int rowZero = 5; // num elements const int rowOne = 2; const int rowTwo = 3; const int rowThree = 5; // declare the jagged array as 4 rows high int[][] jaggedArray = new int[rows][]; // declare the rows of various lengths jaggedArray[0] = new int[rowZero]; jaggedArray[1] = new int[rowOne]; jaggedArray[2] = new int[rowTwo]; jaggedArray[3] = new int[rowThree]; // Fill some (but not all) elements of the rows jaggedArray[0][3] = 15; jaggedArray[1][1] = 12; jaggedArray[2][1] = 9; jaggedArray[2][2] = 99; jaggedArray[3][0] = 10; jaggedArray[3][1] = 11; jaggedArray[3][2] = 12; jaggedArray[3][3] = 13; jaggedArray[3][4] = 14; for (int i = 0;i < rowZero; i++) { Console.WriteLine("jaggedArray[0][{0}] = {1}", i,jaggedArray[0][i]); } for (int i = 0;i < rowOne; i++) { Console.WriteLine("jaggedArray[1][{0}] = {1}", i,jaggedArray[1][i]); } for (int i = 0;i < rowTwo; i++) { Console.WriteLine("jaggedArray[2][{0}] = {1}", i,jaggedArray[2][i]); } for (int i = 0;i < rowThree; i++) { Console.WriteLine("jaggedArray[3][{0}] = {1}", i,jaggedArray[3][i]); } } [STAThread] static void Main() { Tester t = new Tester(); t.Run(); } } } output: jaggedArray[0][0] = 0 jaggedArray[0][1] = 0 jaggedArray[0][2] = 0 jaggedArray[0][3] = 15 jaggedArray[0][4] = 0 jaggedArray[1][0] = 0 jaggedArray[1][1] = 12 jaggedArray[2][0] = 0 jaggedArray[2][1] = 9 jaggedArray[2][2] = 99 jaggedArray[3][0] = 10 jaggedArray[3][1] = 11 jaggedArray[3][2] = 12 jaggedArray[3][3] = 13 jaggedArray[3][4] = 14 Example 15-8 creates a jagged array with four rows: int[][] jaggedArray = new int[rows][]; Notice that the size of the second dimension is not specified. The columns in a jagged array vary by row; thus they are set by creating a new array for each row. Each of these arrays can have a different size: jaggedArray[0] = new int[rowZero]; jaggedArray[1] = new int[rowOne]; jaggedArray[2] = new int[rowTwo]; jaggedArray[3] = new int[rowThree]; If you look back at the values of the constants (rowZero through rowThree), you'll be able to figure out that there are 15 slots in this array. Once an array size is specified for each row, you need to populate the various members of each array (row) and then print out their contents to ensure that all went as expected. |