Jump to content

Finding Elements in C# 4.0

0
  chco's Photo
Posted Aug 16 2010 11:30 AM

In this excerpt from Programming C# 4.0, Sixth Edition the author offers several ways of working with elements and different ways to code more efficiently.
Suppose we want to find out if an array of calendar items contains any events that start on a particular date. An obvious way to do this would be to write a loop that iterates through all of the elements in the array, looking at each date in turn (see Example 7-13).

Example 7-13. Finding elements with a loop

DateTime dateOfInterest = new DateTime (2009, 7, 12);
foreach (CalendarEvent item in events)
{
    if (item.StartTime.Date == dateOfInterest)
    {
        Console.WriteLine(item.Title + ": " + item.StartTime);
    }
}



Note: Example 7-13 relies on a useful feature of the DateTimeOffset type that makes it easy to work out whether two DateTimeOffset values fall on the same day, regardless of the exact time. The Date property returns a DateTime in which the year, month, and day are copied over, but the time of day is set to the default time of midnight.



Although Example 7-13 works just fine, the Array class provides an alternative: its FindAll method builds a new array containing only those elements in the original array that match whatever criteria you specify. Example 7-14 uses this method to do the same job as Example 7-13.

Example 7-14. Finding elements with FindAll

DateTime dateOfInterest = new DateTime (2009, 7, 12);
CalendarEvent[] itemsOnDateOfInterest = Array.FindAll(events,
    e => e.StartTime.Date == dateOfInterest);

foreach (CalendarEvent item in itemsOnDateOfInterest)
{
    Console.WriteLine(item.Title + ": " + item.StartTime);
}


Notice that we’re using a lambda expression to tell FindAll which items match. That’s not mandatory—FindAll requires a delegate here, so you can use any of the alternatives discussed in Chapter 5, including lambda expressions, anonymous methods, method names, or any expression that returns a suitable delegate. The delegate type here is Predicate<T>, where T is the array element type (Predicate<CalendarEvent> in this case). We also discussed predicate delegates in Chapter 5, but in case your memory needs refreshing, we just need to supply a function that takes a CalendarEvent and returns true if it matches, and false if it does not. Example 7-14 uses the same expression as the if statement in Example 7-13.

This may not seem like an improvement on Example 7-13. We’ve not written any less code, and we’ve ended up using a somewhat more advanced language feature—lambda expressions—to get the job done. However, notice that in Example 7-14, we’ve already done all the work of finding the items of interest before we get to the loop. Whereas the loop in Example 7-13 is a mixture of code that works out what items we need and code that does something with those items, Example 7-14 keeps those tasks neatly separated. And if we were doing more complex work with the matching items, that separation could become a bigger advantage—code tends to be easier to understand and maintain when it’s not trying to do too many things at once.

The FindAll method becomes even more useful if you want to pass the set of matching items on to some other piece of code, because you can just pass the array of matches it returns as an argument to some method in your code. But how would you do that with the approach in Example 7-13, where the match-finding code is intermingled with the processing code? While the simple foreach loop in Example 7-13 is fine for trivial examples, FindAll and similar techniques (such as LINQ, which we’ll get to in the next chapter) are better at managing the more complicated scenarios likely to arise in real code.


Note: This is an important principle that is not limited to arrays or collections. In general, you should try to construct your programs by combining small pieces, each of which does one well-defined job. Code written this way tends to be easier to maintain and to contain fewer bugs than code written as one big, sprawling mass of complexity. Separating code that selects information from code that processes information is just one example of this idea.



The Array class offers a few variations on the FindAll theme. If you happen to be interested only in finding the first matching item, you can just call Find. Conversely, FindLast returns the very last matching item.

Sometimes it can be useful to know where in the array a matching item was found. So as an alternative to Find and FindLast, Array also offers FindIndex and FindLastIndex, which work in the same way except they return a number indicating the position of the first or last match, rather than returning the matching item itself.

Finally, one special case for finding the index of an item turns out to crop up fairly often: the case where you know exactly which object you’re interested in, and just need to know where it is in the array. You could do this with a suitable predicate, for example:

int index = Array.FindIndex(events, e => e == someParticularEvent);


But Array offers the more specialized IndexOf and LastIndexOf, so you only have to write this:

int index = Array.IndexOf(events, someParticularEvent);


Cover of Programming C# 4.0
Learn more about this topic from Programming C# 4.0. 

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.

Learn More Read Now on Safari


Tags:
0 Subscribe


0 Replies