Finding elements by position (first, last, Nth)
This next installment (the first examining the May CTP), looks at the Element operators, which are extension methods that return elements from a query based on its location in the result sequence.
The first Element operator sample (LINQ 58) shows how to extract just the first element using a query:
Product product12 = (
from p in products
where p.ProductID == 12
select p )
.First();
Incredibly simple: .First() returns the first element. As I’ve discussed earlier, the First() method is an extension method defined in Sequence.cs.
KEY POINT: LINQ queries produce a sequence, not a collection. That means this does not enumerate the entire collection, the enumeration stops when the First() method returns an element. That means you don’t retrieve all products, just the ones you ask about. First is much more useful when you combine it with a condition. The next sample retrieves the first string from an array that starts with an ‘o’:
string[] strings = { "zero", "one", "two", "three", "four",
"five", "six", "seven", "eight", "nine" };string startsWithO = strings.First(s => s[0] == 'o');
This is all well and good, but what happens if the element you seek isn’t found? If you use First(), it throws an exception. That may be bad. In those cases, use FirstOrDefault:
int[] numbers = {};
int firstNumOrDefault = numbers.FirstOrDefault();firstNumOrDefault will be assigned the value of 0. There are no numbers, so FirstOrDefault returns the default value (in this case, default(int)
FirstOrDefault is more useful when you use a predicate to find a particular element. The next query looks for a particular element, and if the element is not found, it returns a default new product?
List<Product> products = GetProductList();
Product product789 = products.FirstOrDefault
(p => p.ProductID == 789);
If there is a product with ID 789, that element is returned. Otherwise, it returns null.
Of course, there are many times you don’t necessarily want the first element. So, if you want the second element, you use the ElementAt() extension method:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int fourthLowNum = (
from n in numbers
where n > 5
select n )
.ElementAt(1); The 101 queries sample does not include the full catalog of related methods, but there are several other methods that perform related functionality:
Last()
Last(predicate)
LastOrDefault()
LastOrDefault(predicate)
ElementAt(predicate)
But, there’s more to life than queries, The LINQ libraries provide generation methods that fill sequences for you. The Range method generates a sequence of elements, starting with the nth element, and producing k elements. This statement produces the numbers 100 – 149:
var numbers =
from n in Sequence.Range(100, 50)
select new {Number = n, OddEven = n % 2 ==
1 ? "odd" : "even"};
Range() has two different version. One that is specialized for integers, which generates a list of numbers, simply relying on the order of numbers. The second version produces a sub-range from any arbitrary IEnumerable<T> source.
Finally, the Repeat() extension method returns the same element N times. (Note that if the element to be returned is a reference type, you get N references to the same actual storage, not N different copies of the same element.
var numbers = Sequence.Repeat(7, 10);
The above statement generates a sequence containing the number ‘7’ ten times.
That’s it for this entry. Later this week, I’ll return with quantifiers. Have fun.
Part 1
The general query syntax
Part 2
The one where I discuss Object and Collection Initializers
Part 3
The one where I finish restriction operators
Part 4
Beginning to discuss projections
Part 5
Anonymous types and projections
Part 6
Discussing indexed, filtered, and compound queries
Part 7
Finishing up the projection items
Part 8
Projection operators and extension methods
Part 9
OrderBy, ThenBy, and Descending, Oh my
Part 10
Grouping operators, and building nested groups
Part 11
Set Operations, You bet.
Part 12
Conversions: caching collections