Arrays are basically lists of sequentially accessible data. They provide a means of accessing and storing data in a way that allows multiple related elements to be manipulated via numeric index. This section shows you how to declare and use arrays within your code, including using multidimensional arrays and nested or jagged arrays. Declaring and Initializing ArraysTo differentiate between a single value and an array value, the array indexer notation is used. This notation is represented by the square brackets [and]. To properly declare an array, you need to indicate the data type of the individual elements of the array. This data type is what precedes the [] notation in the sample array declarations that follow: byte[] byteValues; int[] counts; string[] words; Object[] objList; Customer[] customers; Unlike with some other languages, in C# you don't specify the size of the array in the declaration portion. So, to specify an array of 12 elements, you cannot declare that as follows: byte[12] byteArray; Initializing the array is what provides C# with the boundary information on the array. Because arrays are essentially just specialized classes, you initialize them with the new keyword, as shown in the following samples: byte[] byteArray = new byte[21]; int[] counters = new int[99]; string[] wordList = new string[21]; The preceding code initializes empty arrays out to a given length. These can then be populated programmatically from any number of sources, such as user input, XML files, or a relational database. Keep in mind that if you attempt to use an array that has not been initialized, you will get an error. If you know the data that will be in the arrays at design time, you can pre-initialize the arrays with data as shown in the following samples: byte[] byteArray = new byte[] { 1, 2, 3 }; byte[] byteArray2 = { 1, 2, 3 }; string[] wordList = { "The", "Quick", "Brown", "Fox" }; Using One-Dimensional ArraysYou can do many different things with a one-dimensional array. Because arrays are classes, you can press the "." key at the end of any array variable to bring up IntelliSense and get a list of operations that are available to you for a given array, as shown in Figure 4.1. Figure 4.1. IntelliSense for an Array object.
Tables 4.1 and 4.2 describe some of the properties and methods that are provided by the Array class.
Take a look at the code in Listing 4.1, which illustrates how to make use of some of the methods and properties listed in Tables 4.1 and 4.2. Listing 4.1. One-Dimensional Array Manipulation
The code for the FindAll and ForEach methods might appear to be a little odd if you are used to working with C# 1.1. Underneath those methods lies the power of Generics, which you will be introduced to in Chapter 6, "Introduction to Generics." You don't need to know every detail about how it works now because it will become clearer as you continue through the book. The good thing to know is that working with arrays in C# 2.0 is even easier than it was in the previous release. Using Multidimensional ArraysMultidimensional arrays are, as the name states, arrays with more than one dimension. This means that these arrays require multiple indices when accessing data contained within the array. Before taking a look at code that utilizes multidimensional arrays, you should be familiar with why you might want to use arrays with two, three, or even more dimensions. One of the most common uses for 2D arrays is the storage of data in a Cartesian coordinate system (data that has an X and a Y coordinate location). These coordinates are found virtually everywhere you look in Windows Forms application because all controls have an X and a Y location. So, assume that you had a grid that contained controls. You might access the control in the third column of the second row with the following code: Control myControl = controlArray[2, 1]; Note that I used [2,1] to access the data instead of [3,2]. This is because arrays are zero-indexed, so the first element is at index 0, the second element is at index 1, and the third element is at index 2. You can use two-dimensional arrays for any kind of data that can be expressed as a matrix (rectangular grid of data), such as the game board for a game of checkers or tic-tac-toe, or a spreadsheet containing sales values of various products organized by month. Three-dimensional arrays are typically used to represent cube-shaped data. For example, you can use three-dimensional arrays to supply the information for Excel-style pivot tables, or you can use a 3D array to support three-dimensional location coordinates that include an X, Y, and Z location value. Arrays with four or more dimensions can quickly become extremely difficult to maintain and are often extremely confusing when someone is attempting to read code involving arrays with four or more dimensions. These types of arrays are usually reserved for data with very specific requirements that are beyond the scope of this book. The rules for four-dimensional arrays are the same as the rules for two- and three-dimensional arrays, so your code will look similar. You declare a multidimensional array by using a comma to indicate the presence of multiple dimensions in the array, as shown in the following example: byte[,] twoDByteArray; // two-dimensional array of bytes SpaceShip[,,] objectsInSpace; // stores ships that exist in various coordinates PlayerPiece[,] checkerBoard; // stores pieces on a checkerboard The number of commas indicates the number of dimensions. As with single-dimension arrays, you cannot specify the maximum bounds of each dimension in the declaration; you can only specify it in the initialization. In addition, you may have noticed that there is no way to specify the minimum bounds. This is because in C#, all arrays start with the 0 index. In the sample shown in Listing 4.2, you will see some code that works with two-dimensional arrays as well as one-dimensional arrays. The sample creates an array of month names and an array of product names. These arrays will be used as the labels for the rows and columns in a spreadsheet-style output that shows total product sales for each month. The product names will run vertically down the left side, and the month names run horizontally along the top. In the middle of the spreadsheet, the product sales values will be displayed using a two-dimensional array as the source. Listing 4.2. Two-Dimensional Array Sample
The output of the preceding code looks as follows (with a few months cut out to make the display fit on a page): | Jan | Feb | Mar | Apr | May PROD1: 0 | 1 | 2 | 3 | 4 PROD2: 1 | 2 | 3 | 4 | 5 PROD3: 2 | 3 | 4 | 5 | 6 PROD4: 3 | 4 | 5 | 6 | 7 PROD5: 4 | 5 | 6 | 7 | 8 Using Jagged ArraysThe preceding section dealt with rectangular arrays, in which the number of columns (elements) would be the same for each row, giving you data that is shaped like a matrix. Jagged arrays are arrays whose elements are also arrays. A jagged array (also referred to as an array of arrays) is an array (single-dimension or multidimensional) in which the elements are themselves arrays. This allows each element of the array to be an array with a different size. There are many ways to declare jagged arrays, some of which take advantage of the same initializer shortcuts that are available for other array types. The following few lines of code declare a jagged array without doing any initialization: string[][] jaggedStrings; int[][] jaggedInts; Customer[][] jaggedCustomers; Note that instead of declaring it with the comma notation indicating a multidimensional array, the "Array of Arrays" notation is used, which is two array bracket symbols: [][]. The following lines of code illustrate a few of the ways in which you can initialize jagged arrays, including some of the shortcuts that allow you to omit the new keyword when providing the initial values for the array: int[][] jaggedInts = new int[2][]; jaggedInts[0] = new int[10]; jaggedInts[1] = new int[20]; int[][] ji2 = new int[2][]; ji2[0] = new int[] { 1, 3, 5, 7, 9 }; ji2[1] = new int[] { 2, 4, 6 }; // doesn't need the initial 'new int[][]' , // compiler can infer it int[][] ji3 = { new int[] { 1, 3, 5, 7, 9 }, new int[] { 2, 4, 6 } }; // 'new int[][]' used explicitly, though it isn't // needed. int[][] ji4 = new int[][] { new int[] { 1, 3, 5, 7, 9 }, new int[] { 2, 4, 6 } }; As confusing as it might seem, you can mix jagged and rectangular arrays to create some powerful (and often difficult to decipher) structures. Take a look at the following code, which creates a jagged array in which each element is a different-size two-dimensional array: int[][,] mixedJagged = new int[][,] { new int[,] { {0,1}, {2,3}, {4,5} }, new int[,] { {9,8}, {7,6}, {5,4}, {3,2}, {1,0} } }; Console.WriteLine(mixedJagged[1][1, 1]); Console.ReadLine(); The preceding code declares the jagged array of two-dimensional arrays and will print the value 6. By accessing element 1 in the first dimension, the code is referencing the second multidimensional array. Then, the indexer [1,1] indicates the second pair of numbers, and the second number within that pair: 6. The code in Listing 4.3 uses jagged arrays to display the list of the top-selling products during each month. The data here is fabricated, but real data would come from a relational data source such as SQL Server or an XML file (or XML from a web service) in a production application. Listing 4.3. Jagged Array Demonstration
One of the most important pieces of the preceding code is the looping through the arrays. Note that we don't actually know the size of the array in each element of the first dimension of the jagged array. We have to obtain that length dynamically by checking: productSales[month].Length The other thing is that the preceding code won't work if one of the elements in the first dimension is null, so your production code should have additional safety checks to prevent Null Reference exceptions. The output of the preceding code is as follows: Happy Toy Company Top Sellers By Month April: --------- Rubber Band Bouncy Ball Sticky Goo May: --------- Rock Candy Rubber Band Bouncy Ball Sticky Goo June: --------- Little Giant Dynamite Stick ACME Inferno Ball of Flame Portable Detonator Caps |