8.9 Multidimensional Arrays

Two-dimensional arrays are often used to represent tables of values consisting of information arranged in rows and columns. To identify a particular table element, we must specify two indices. By convention, the first identifies the element’s row and the second its column. (Multidimensional arrays can have more than two dimensions, but such arrays are beyond the scope of this book.) C# supports two types of two-dimensional arrays—rectangular arrays and jagged arrays.

8.9.1 Rectangular Arrays

Rectangular arrays are used to represent tables of information in the form of rows and columns, where each row has the same number of columns. Figure 8.17 illustrates a rectangular array named a containing three rows and four columns—a three-by-four array. In general, an array with m rows and n columns is called an m-by-n array.

Fig. 8.17 Rectangular array with three rows and four columns.

Array-Access Expression for a Two-Dimensional Rectangular Array

Every element in array a is identified in Fig. 8.17 by an array-access expression of the form a[row, column]; a is the name of the array, and row and column are the indices that uniquely identify each element in array a by row and column number. The names of the elements in row 0 all have a first index of 0, and the names of the elements in column 3 all have a second index of 3.

Array Initializer for a Two-Dimensional Rectangular Array

Like one-dimensional arrays, multidimensional arrays can be initialized with array initializers in declarations. A rectangular array b with two rows and two columns could be declared and initialized with nested array initializers as follows:


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

The initializer values are grouped by row in braces. So, 1 and 2 initialize b[0, 0] and b[0, 1], respectively, and 3 and 4 initialize b[1, 0] and b[1, 1], respectively. The compiler counts the number of nested array initializers (represented by sets of two inner braces within the outer braces) in the initializer list to determine the number of rows in array b. The compiler counts the initializer values in the nested array initializer for a row to determine the number of columns (two) in that row. The compiler will generate an error if the number of initializers in each row is not the same, because every row of a rectangular array must have the same length (i.e., the same number of columns.

8.9.2 Jagged Arrays

A jagged array is maintained as a one-dimensional array in which each element refers to a one-dimensional array. The manner in which jagged arrays are represented makes them quite flexible, because the lengths of the rows in the array need not be the same. For example, jagged arrays could be used to store a single student’s exam grades across multiple courses, where the number of exams may vary from course to course.

Array Initializer for a Two-Dimensional Jagged Array

We can access the elements in a jagged array by an array-access expression of the form arrayName[row][column]—similar to the array-access expression for rectangular arrays, but with a separate set of square brackets for each dimension. A jagged array with three rows of different lengths could be declared and initialized as follows:


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

In this statement, 1 and 2 initialize jagged[0][0] and jagged[0][1], respectively; 3 initializes jagged[1][0]; and 4, 5 and 6 initialize jagged[2][0], jagged[2][1] and jagged[2][2], respectively. Therefore, array jagged in the preceding declaration is actually composed of four separate one-dimensional arrays—one that represents the rows, one containing the values in the first row ({1, 2}), one containing the value in the second row ({3}) and one containing the values in the third row ({4, 5, 6}). Thus, array jagged itself is an array of three elements, each a reference to a one-dimensional array of int values.

Diagram of a Two-Dimensional Jagged Array in Memory

Observe the differences between the array-creation expressions for rectangular arrays and for jagged arrays. Two sets of square brackets follow the type of jagged, indicating that this is an array of int arrays. Furthermore, in the array initializer, C# requires the keyword new to create an array object for each row. Figure 8.18 illustrates the array reference jagged after it’s been declared and initialized.

Fig. 8.18 Jagged array with three rows of different lengths.

Creating Two-Dimensional Arrays with Array-Creation Expressions

A rectangular array can be created with an array-creation expression. For example, the following lines declare variable b and assign it a reference to a three-by-four rectangular array:


int[,] b;
b = new int[3, 4];

In this case, we use the literal values 3 and 4 to specify the number of rows and number of columns, respectively, but this is not required—apps also can use variables and expressions to specify array dimensions. As with one-dimensional arrays, the elements of a rectangular array are initialized when the array object is created.

A jagged array cannot be completely created with a single array-creation expression. The following statement is a syntax error:


int[][] c = new int[2][5]; // error

Instead, each one-dimensional array in the jagged array must be initialized separately. A jagged array can be created as follows:


int[][] c;
c = new int[2][]; // create 2 rows
c[0] = new int[5]; // create 5 columns for row 0
c[1] = new int[3]; // create 3 columns for row 1

The preceding statements create a jagged array with two rows. Row 0 has five columns, and row 1 has three columns.

8.9.3 Two-Dimensional Array Example: Displaying Element Values

Figure 8.19 demonstrates initializing rectangular and jagged arrays with array initializers and using nested for loops to traverse the arrays (i.e., visit every element of each array). Class InitArray’s Main method creates two arrays. Line 12 uses nested array initializers to initialize variable rectangular with an array in which row 0 has the values 1, 2 and 3, and row 1 has the values 4, 5 and 6. Lines 17–19 use nested initializers of different lengths to initialize variable jagged. In this case, the initializer uses the keyword new to create a one-dimensional array for each row. Row 0 is initialized to have two elements with values 1 and 2, respectively. Row 1 is initialized to have one element with value 3. Row 2 is initialized to have three elements with the values 4, 5 and 6, respectively.

Fig. 8.19 Initializing jagged and rectangular arrays.

Alternate View

  1   // Fig. 8.19: InitArray.cs
  2   // Initializing rectangular and jagged arrays.
  3   using System;
  4
  5   class InitArray
  6   {
  7      // create and output rectangular and jagged arrays
  8      static void Main()
  9      {
 10         // with rectangular arrays,
 11         // every row must be the same length.
 12         int[,] rectangular = {{1, 2, 3}, {4, 5, 6}};
 13
 14         // with jagged arrays,
 15         // we need to use "new int[]" for every row,
 16         // but every row does not need to be the same length.
 17         int[][] jagged = {new int[] {1, 2},    
 18                           new int[] {3},       
 19                           new int[] {4, 5, 6}};
 20
 21         OutputArray(rectangular); // displays array rectangular by row
 22         Console.WriteLine(); // output a blank line
 23         OutputArray(jagged); // displays array jagged by row
 24      }
 25
 26      // output rows and columns of a rectangular array
 27      static void OutputArray(int[,] array  )
 28      {
 29         Console.WriteLine("Values in the rectangular array by row are");
 30
 31         // loop through array's rows                                           
 32         for (var row = 0; row < array.GetLength(0); ++row)                     
 33         {                                                                      
 34            // loop through columns of current row                              
 35            for (var column = 0; column < array.GetLength(1); ++column)         
 36            {                                                                   
 37               Console.Write($"{array[row, column]} ");                         
 38            }                                                                   
 39                                                                                
 40            Console.WriteLine(); // start new line of output                    
 41         }                                                                      
 42      }
 43
 44      // output rows and columns of a jagged array
 45      static void OutputArray(int[][] array)
 46      {
 47         Console.WriteLine("Values in the jagged array by row are");
 48
 49         // loop through each row                           
 50          foreach (var row in array)                        
 51         {                                                  
 52            // loop through each element in current row     
 53            foreach (var element in row)                    
 54            {                                               
 55            Console.Write($"{element} ");                   
 56            }                                               
 57                                                            
 58            Console.WriteLine(); // start new line of output
 59         }                                                  
 60      }
 61   }

Values in the rectangular array by row are
1   2   3
4   5   6

Values in the jagged array by row are
1   2
3
4   5   6

Overloaded Method OutputArray

Method OutputArray is overloaded. The first version (lines 27–42) specifies the array parameter as int[,] array to indicate that it takes a rectangular array. The second version (lines 45–60) takes a jagged array, because its array parameter is listed as int[][] array.

Method OutputArray for Rectangular Arrays

Line 21 invokes method OutputArray with argument rectangular, so the version of OutputArray at lines 27–42 is called. The nested for statement (lines 32–41) outputs the rows of a rectangular array. The loop-continuation condition of each for statement (lines 32 and 35) uses the rectangular array’s GetLength method to obtain the length of each dimension. Dimensions are numbered starting from 0, so the method call GetLength(0) on array returns the size of the first dimension of the array (the number of rows), and the call GetLength(1) returns the size of the second dimension (the number of columns). A foreach statement also can iterate through all the elements in a rectangular array. In this case, foreach iterates through all the rows and columns starting from row 0, as if the elements were in a one-dimensional array.

Method OutputArray for Jagged Arrays

Line 23 invokes method OutputArray with argument jagged, so OutputArray at lines 45– 60 is called. The nested foreach statement (lines 50–59) outputs the rows of a jagged array. The inner foreach statement (lines 53–56) iterates through each element in the current row. This allows the loop to determine the exact number of columns in each row. Since the jagged array is created as an array of arrays, we can use nested foreach statements to output the elements in the console window. The outer loop iterates through the elements of array, which are references to one-dimensional arrays of int values that represent each row. The inner loop iterates through the elements of the current row.

Common Multidimensional-Array Manipulations Performed with for Statements

Many common array manipulations use for statements. As an example, the following for statement sets all the elements in row 2 of rectangular array a in Fig. 8.17 to 0:


for (int column = 0; column < a.GetLength(1); ++column)
{
   a[2, column] = 0;
}

We specified row 2; therefore, we know that the first index is always 2 (0 is the first row, and 1 is the second row). This for loop varies only the second index (i.e., the column index). The preceding for statement is equivalent to the assignment statements


a[2, 0] = 0;
a[2, 1] = 0;
a[2, 2] = 0;
a[2, 3] = 0;

The following nested for statement totals the values of all the elements in array a:


int total = 0;

for (int row = 0; row < a.GetLength(0); ++row)
{
   for (int column = 0; column < a.GetLength(1); ++column)
   {
      total += a[row, column];
   }
}

These nested for statements total the array elements one row at a time. The outer for statement begins by setting the row index to 0 so that row 0’s elements can be totaled by the inner for statement. The outer for then increments row to 1 so that row 1’s elements can be totaled. Then the outer for increments row to 2 so that row 2’s elements can be totaled. The variable total can be displayed when the outer for statement terminates. In the next example, we show how to process a rectangular array in a more concise manner using foreach statements.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset