As we said earlier, you can make an array using any type as the element type. And since arrays themselves have types, it follows that you can have an array of arrays. For example, suppose we wanted to create a list of forthcoming events over the next five days, grouped by day. We could represent this as an array with one entry per day, and since each day may have multiple events, each entry needs to be an array. Example 7-20 creates just such an array.
Example 7-20. Building an array of arrays
static CalendarEvent[][] GetEventsByDay(CalendarEvent[] allEvents,
DateTime firstDay,
int numberOfDays)
{
CalendarEvent[][] eventsByDay = new CalendarEvent[numberOfDays][];
for (int day = 0; day < numberOfDays; ++day)
{
DateTime dateOfInterest = (firstDay + TimeSpan.FromDays(day)).Date;
CalendarEvent[] itemsOnDateOfInterest = Array.FindAll(allEvents,
e => e.StartTime.Date == dateOfInterest);
eventsByDay[day] = itemsOnDateOfInterest;
}
return eventsByDay;
}We’ll look at this one piece at a time. First, there’s the method declaration:
static CalendarEvent[][] GetEventsByDay(CalendarEvent[] allEvents,
DateTime firstDay,
int numberOfDays)
{The return type—CalendarEvent[][]—is an array of arrays, denoted by two pairs of square brackets. You’re free to go as deep as you like, by the way—it’s perfectly possible to have an array of arrays of arrays of arrays of anything.
The method’s arguments are fairly straightforward. This method expects to be passed a simple array containing an unstructured list of all the events. The method also needs to know which day we’d like to start from, and how many days we’re interested in.
The very first thing the method does is construct the array that it will eventually return:
CalendarEvent[][] eventsByDay = new CalendarEvent[numberOfDays][];
Just as new CalendarEvent[5] would create an array capable of containing five CalendarEvent elements, new CalendarEvent[5][] would create an array capable of containing five arrays of CalendarEvent objects. Since our method lets the caller specify the number of days, we pass that argument in as the size of the top-level array.
Remember that arrays are reference types, and that whenever you create a new array whose element type is a reference type, all the elements are initially null. So although our new eventsByDay array is capable of referring to an array for each day, what it holds right now is a null for each day. So the next bit of code is a loop that will populate the array:
for (int day = 0; day < numberOfDays; ++day)
{
...
}Inside this loop, the first couple of lines are similar to the start of Example 7-14:
DateTime dateOfInterest = (firstDay + TimeSpan.FromDays(day)).Date;
CalendarEvent[] itemsOnDateOfInterest = Array.FindAll(allEvents,
e => e.StartTime.Date == dateOfInterest);The only difference is that this example calculates which date to look at as we progress through the loop. So Array.FindAll will return an array containing all the events that fall on the day for the current loop iteration. The final piece of code in the loop puts that into our array of arrays:
eventsByDay[day] = itemsOnDateOfInterest;
Once the loop is complete, we return the array:
return eventsByDay;
}Each element will contain an array with the events that fall on the relevant day.
Code that uses such an array can use the normal element access syntax, for example:
Console.WriteLine("Number of events on first day: " + eventsByDay[0].Length);Notice that this code uses just a single index—this means we want to retrieve one of the arrays from our array of arrays. In this case, we’re looking at the size of the first of those arrays. Or we can dig further by providing multiple indexes:
Console.WriteLine("First day, second event: " + eventsByDay[0][1].Title);This syntax, with its multiple sets of square brackets, fits right in with the syntax used to declare and construct the array of arrays.
So why is an array of arrays sometimes called a jagged array? Figure 7-4 shows the various objects you would end up with if you called the method in Example 7-20, passing the events from Example 7-10, asking for five days of events starting from July 11. The figure is laid out to show each child array as a row, and as you can see, the rows are not all the same length—the first couple of days have two items per row, the third day has one, and the last two are empty (i.e., they are zero-length arrays). So rather than looking like a neat rectangle of objects, the rows form a shape with a somewhat uneven or “jagged” righthand edge.
This jaggedness can be either a benefit or a problem, depending on your goals. In this example, it’s helpful—we used it to handle the fact that the number of events in our calendar may be different every day, and some days may have no events at all. But if you’re working with information that naturally fits into a rectangular structure (e.g., pixels in an image), rows of differing lengths would constitute an error—it would be better to use a data structure that doesn’t support such things, so you don’t have to work out how to handle such an error.
Moreover, jagged arrays end up with a relatively complicated structure—there are a lot of objects in Figure 7-4. Each array is an object distinct from the objects its element refers to, so we’ve ended up with 11 objects: the five events, the five per-day arrays (including two zero-length arrays), and then one array to hold those five arrays. In situations where you just don’t need this flexibility, there’s a simpler way to represent multiple rows: a rectangular array.
This bestselling tutorial shows you how to build web, desktop, and rich Internet applications using C# 4.0 with .NET's database capabilities, UI framework (WPF), extensive communication services (WCF), and more. The sixth edition covers the latest enhancements to C#, as well as the fundamentals of both the language and framework. You'll learn concurrent programming with C# 4.0, and how to use .NET tools such as the Entity Framework for easier data access, and the Silverlight platform for browser-based RIA development.




Help






