Section 6.1.


6.1.

6.1.1. Aggregate

The Aggregate operator applies a function over a sequence, with or without an initial seed value. The result can be post-processed by another function is desired.

 int[] ints  = { 1, 2, 3, 4, 5, 6 }; var   query = from ...; int sum     = ints.Aggregate( (a, b) => a + b ); int product = ints.Aggregate( 1, (a, b) => a * b ); int sump1   = ints.Aggregate( 0, (a, b) => a + b, r => r+1 ); var result  = query.Aggregate(...); Console.WriteLine(sum);      // 21 Console.WriteLine(product);  // 720 Console.WriteLine(sump1);    // 22 Console.WriteLine(result); 

The sequence can be of any type T.

See also: Average, Count, LongCount, Max, Min, and Sum.

Table 1. List of Standard LINQ Query Operators

Operator

Lazy?

Description

Aggregate

No

Applies a function to a sequence, yielding a single value.

All

No

Applies a function to a sequence to see if all elements satisfy the function.

Any

No

Applies a function to a sequence to see if any element satisfies the function.

Average

No

Computes the average of a numeric sequence.

Cast

Yes

Yields the elements of a sequence type-casted to a given type.

Concat

Yes

Yields the concatenation of two sequences S1 and S2.

Contains

No

Searches a sequence to see if it contains a given element.

Count

No

Counts the number of elements in a sequence, yielding an integer result.

DefaultIfEmpty

Yes

Given a sequence S, yields S or a sequence with the default value if S is empty.

Distinct

Yes

Returns a sequence with duplicates eliminated.

ElementAt

No

Returns the ith element of a sequence.

ElementAtOrDefault

No

Returns the ith element of a sequence, or the default value if sequence is empty.

Empty

Yes

Yields an empty sequence.

EqualAll

No

Compares two sequences for equality.

Except

Yes

Given two sequences S1 and S2, returns the set difference S1 S2.

First

No

Returns the first element of a sequence.

FirstOrDefault

No

Returns the first element of a sequence, or the default value if sequence is empty.

Fold

No

Obsolete, see Aggregate.

GroupBy

Yes

Groups the elements of a sequence by key.

GroupJoin

Yes

Performs a join of two sequences S1 and S2, yielding a hierarchical result.

Intersect

Yes

Given two sequences S1 and S2, returns the set intersection of S1 and S2.

Join

Yes

Performs a traditional inner equijoin of two sequences S1 and S2.

Last

No

Returns the last element of a sequence.

LastOrDefault

No

Returns the last element of a sequence, or the default value if sequence is empty.

LongCount

No

Counts the number of elements in a sequence, yielding a long result.

Max

No

Returns the maximum of a sequence.

Min

No

Returns the minimum of a sequence.

OfType

Yes

Yields the elements of a sequence that match a given type.

OrderBy

Yes

Orders a sequence of elements by key into ascending order.

OrderByDescending

Yes

Orders a sequence of elements by key into descending order.

Range

Yes

Yields a sequence of integers in a given range.

Repeat

Yes

Yields a sequence of values by repeating a given value n times.

Reverse

Yes

Reverses the elements of a sequence.

Select

Yes

Applies a projection function to a sequence, yielding a new sequence.

SelectMany

Yes

Applies a projection function to flatten a sequence of sequences.

Single

No

Returns the lone element of a singleton sequence.

SingleOrDefault

No

Returns the lone element of a singleton sequence, or default if sequence is empty.

Skip

Yes

Skips the first n elements of a sequence, yielding the remaining elements.

SkipWhile

Yes

Given function F and sequence S, skips the initial elements of S where F is true.

Sum

No

Computes the sum of a numeric sequence.

Take

Yes

Yields the first n elements of a sequence.

TakeWhile

Yes

Given function F and sequence S, yields the initial elements of S where F is true.

ThenBy

Yes

Takes an ordered sequence and yields a secondary, ascending ordering.

TheyByDescending

Yes

Takes an ordered sequence and yields a secondary, descending ordering.

ToArray

No

Iterates across a sequence, capturing results in an array.

ToDictionary

No

Iterates across a sequence, capturing results in a Dictionary<K, V>.

ToList

No

Iterates across a sequence, capturing results in a List<T>.

ToLookup

No

Iterates across a sequence, capturing results in a Lookup<K, IEnumerable<V>>.

ToSequence

Yes

Casts a sequence as an IEnumerable sequence for use with standard query ops.

Union

Yes

Given two sequences S1 and S2, returns the set union of S1 and S2.

Where

Yes

Applies a Boolean function to a sequence, yielding a sub-sequence.


6.1.2. All

The All operator applies a function over a sequence, checking to see if all of the elements satisfy the function, i.e., cause the function to return true. For example, do all the doctors have pager numbers? How about all the doctors retrieved by a particular query?

 Doctors doctors = new Doctors(); var query = from doc in doctors ...; bool allHavePagers   = doctors.All(doc => doc.PagerNumber > 0); bool theseHavePagers = query.All(doc => doc.PagerNumber > 0); 

See also: Any, Contains, and EqualAll.

6.1.3. Any

The Any operator applies a function over a sequence, checking to see if any of the elements satisfy the function, i.e., cause the function to return true. For example, are there any doctors living in Lake Forest?

 Doctors doctors = new Doctors(); bool inLakeForest = doctors.Any(doc => doc.City == "Lake Forest"); 

The function is optional; if omitted, the Any operator returns true if the sequence contains at least one element.

 var query = from doc in doctors             where doc.City == "Lake Forest"             select doc; bool inLakeForest = query.Any(); 

See also: All, Contains, and EqualAll.

6.1.4. Average

The Average operator computes the average of a sequence of numeric values. The values are either the sequence itself, or selected out of a sequence of objects.

 int[]      ints    = { 1, 2, 3, 4, 5, 6 }; decimal?[] values  = { 1, null, 2, null, 3, 4 }; Doctors    doctors = new Doctors(); var        query   = from ...; double   avg1     = ints.Average(); decimal? avg2     = values.Average(); double   avgYears = doctors.Average( doc =>                       DateTime.Now.Subtract(doc.StartDate).Days / 365.25 ); var      avg      = query.Average(); Console.WriteLine(avg1);   // 3.5 Console.WriteLine(avg2);   // 2.5 Console.WriteLine(avgYears.ToString("0.00"));   // 5.72 Console.WriteLine(avg); 

The values can be of type int, int?, long, long?, decimal, decimal?, double, or double?. The resulting type is double, double?, double, double?, decimal, decimal?, double, or double?, respectively.

See also: Aggregate, Count, LongCount, Max, Min, and Sum.

6.1.5. Cast

The Cast operator yields the elements of a sequence type-casted to a given type T.

 System.Collections.ArrayList al = new System.Collections.ArrayList(); al.Add("abc"); al.Add("def"); al.Add("ghi"); var strings = al.Cast<string>(); foreach(string s in strings)   // "abc", "def", "ghi"   Console.WriteLine(s); 

The Cast operator is commonly used to wrap pre-2.0 collections (such as ArrayLists) for use with LINQ. Here's a more interesting example of searching the Windows event log for all events logged by an application:

 var entries = from entry in applog.Entries.Cast<System.Diagnostics.EventLogEntry>()               where entry.Source == "ApplicationName"               orderby entry.TimeWritten descending               select entry; 

See also: OfType.

6.1.6. Concat

The Concat operator concatenates two sequences S1 and S2, yielding the elements of S1 followed by the elements of S2.

 int[] ints1  = { 1, 2, 3 }; int[] ints2  = { 4, 5, 6 }; var   query1 = from ...; var   query2 = from ...; var all     = ints1.Concat(ints2); var results = query1.Concat(query2); foreach(var x in all)     // 1, 2, 3, 4, 5, 6   Console.WriteLine(x); foreach(var r in results)   Console.WriteLine(r); 

The sequences may contain elements of any type T. This element type T must be the same at compile-time (e.g. object), but may differ at run-time:

 object[] objects1 = { "abc", "def" }; object[] objects2 = { 1, 2, 3 }; var result = objects1.Concat(objects2); 

See also: Union.

6.1.7. Contains

The Contains operator searches a sequence to see if it contains a given element. For example, is there a doctor with initials "gg" still working at University Hospital? One approach is to create a Doctor object with the initials we are looking for, and see if the collection contains this object:

 Doctors doctors = new Doctors(); bool docExists = doctors.Contains( new Doctor("gg", ...) ); 

This assumes the Doctor class defines Equals based on a doctor's initials. Another approach (without this assumption) is to select all the initials and then see if the result contains the string "gg":

 var query = from doc in doctors             select doc.Initials bool docExists = query.Contains("gg"); 

See also: All, Any, EqualAll, and Where.

6.1.8. Count

The Count operator counts the number of elements in a sequence, yielding an integer result. The elements are either the sequence itself, or selected from a sequence of objects.

 int[]      ints   = { 1, 2, 3, 4, 5, 6 }; decimal?[] values = { 1, null, 2, null, 3 }; IEnumerable<Doctor> doctors = new Doctors(); var        query  = from ...; int count1 = ints.Count(); int count2 = values.Count(); int count3 = doctors.Count(); int count4 = doctors.Count( doc => doc.City == "Chicago" ); int count  = query.Count(); Console.WriteLine(count1);   // 6 Console.WriteLine(count2);   // 5 Console.WriteLine(count3);   // 12 Console.WriteLine(count4);   // 5 Console.WriteLine(count); 

The sequence can be of any type T.

See also: Aggregate, Average, LongCount, Max, Min, and Sum.

6.1.9. DefaultIfEmpty

Given a non-empty sequence, the DefaultIfEmpty operator yields this same sequence. If the sequence is empty, DefaultIfEmpty yields a sequence containing a single default value.

 int[]   ints1   = { 1, 2, 3, 4, 5, 6 }; int[]   ints2   = { }; var     query   = from ...; var  ints   = ints1.DefaultIfEmpty(); var  zero   = ints2.DefaultIfEmpty(); var  minus1 = ints2.DefaultIfEmpty(-1); var  result = query.DefaultIfEmpty(); foreach(int x in ints)     // 1, 2, 3, 4, 5, 6   Console.WriteLine(x); foreach(int x in zero)     // 0   Console.WriteLine(x); foreach(int x in minus1)   // -1   Console.WriteLine(x); foreach(var r in result)   Console.WriteLine(r); 

The sequence can be of any type T; if the sequence is empty and a default value is not provided, the default value for type T is used.

See also: FirstOrDefault, GroupJoin, LastOrDefault, SingleOrDefault, and ElementAtOrDefault.

6.1.10. Distinct

Given a sequence of elements, the Distinct operator returns the same sequence without duplicates.

 int[] ints  = { 1, 2, 2, 3, 2, 3, 4 }; var   query = from ...; var distinctInts    = ints.Distinct(); var distinctResults = query.Distinct(); foreach(var x in distinctInts)  // 1, 2, 3, 4   Console.WriteLine(x); foreach(var r in distinctResults)   Console.WriteLine(r); 

The sequence can be of any type T.

See also: Except, Intersect, and Union.

6.1.11. ElementAt

The ElementAt operator returns the ith element of a sequence; the sequence must be non-empty, and i is 0-based.

 int[]   ints    = { 1, 2, 3, 4, 5, 6 }; Doctors doctors = new Doctors(); var     query   = from ...; int    third  = ints.ElementAt(2); Doctor doctor = doctors.ElementAt(2); var    result = query.ElementAt(i); Console.WriteLine(third);             // 3 Console.WriteLine(doctor.Initials);   // 3rd doc in Chicago: ch Console.WriteLine(result); 

The sequence can be of any type T.

See also: ElementAtOrDefault.

6.1.12. ElementAtOrDefault

The ElementAtOrDefault operator returns the ith element of a possibly empty sequence; i is 0-based.

 int[]   ints1   = { 1, 2, 3, 4, 5, 6 }; int[]   ints2   = { }; Doctors doctors = new Doctors(); var     query   = from ...; int    x1     = ints1.ElementAtOrDefault(2); int    x2     = ints1.ElementAtOrDefault(6); int    x3     = ints2.ElementAtOrDefault(0); Doctor doc1   = doctors.ElementAtOrDefault(2); Doctor doc2   = doctors.ElementAtOrDefault(-1); var    result = query.ElementAtOrDefault(i); Console.WriteLine(x1);             // 3 Console.WriteLine(x2);             // 0 Console.WriteLine(x3);             // 0 Console.WriteLine(doc1 == null);   // False Console.WriteLine(doc2 == null);   // True Console.WriteLine(result); 

The sequence can be of any type T; if the sequence is empty or i is invalid, the default value for type T is returned.

See also: ElementAt.

6.1.13. Empty

The Empty operator yields an empty sequence of the given type.

 var emptyDocs = System.Query.Sequence.Empty<Doctor>(); foreach(var doc in emptyDocs)   // <none>   Console.WriteLine(doc); 

This operator is helpful when you need an empty sequence for another operator or a method argument.

See also: Range and Repeat.

6.1.14. EqualAll

The EqualAll operator compares two sequences for equality. Two sequences are equal if they are of the same length, and contain the same sequence of elements.

 var query1 = from ...; var query2 = from ...; bool equal = query1.EqualAll(query2); 

The sequences may contain elements of any type T. This element type T must be the same at compile-time (e.g. object), but may differ at run-time:

 object[] objects1 = { "abc", "def" }; object[] objects2 = { 1, 2, 3 }; bool isFalse = objects1.EqualAll(objects2);  // false 

The result in such cases is false.

See also: All, Any, and Contains.

6.1.15. Except

Given two sequences of elements S1 and S2, the Except operator returns the distinct elements of S1 not in S2. In other words, Except computes the set difference S1 S2.

 int[] intsS1 = { 1, 2, 2, 3, 2, 3, 4, 5, 6 }; int[] intsS2 = { 1, 3, 6, 7 }; var   query1 = from ...; var   query2 = from ...; var diffInts    = intsS1.Except(intsS2); var diffResults = query1.Except(query2); foreach(var x in diffInts)  // 2, 4, 5   Console.WriteLine(x); foreach(var r in diffResults)   Console.WriteLine(r); 

The sequences may contain elements of any type T. This element type T must be the same at compile-time (e.g. object), but may differ at run-time:

 object[] objects1 = { "abc", "def" }; object[] objects2 = { 1, 2, 3 }; var result = objects1.Except(objects2); 

See also: Distinct, Intersect, and Union.

6.1.16. First

The First operator returns the first element of a sequence; the sequence must be non-empty.

 int[]   ints    = { 1, 2, 3, 4, 5, 6 }; Doctors doctors = new Doctors(); var     query   = from ...; int    first  = ints.First(); Doctor doctor = doctors.First(doc => doc.City == "Chicago"); var    result = query.First(); Console.WriteLine(first);             // 1 Console.WriteLine(doctor.Initials);   // mbl Console.WriteLine(result); 

The sequence can be of any type T.

See also: FirstOrDefault.

6.1.17. FirstOrDefault

The FirstOrDefault operator returns the first element of a possibly empty sequence.

 int[]   ints1   = { 1, 2, 3, 4, 5, 6 }; int[]   ints2   = { }; Doctors doctors = new Doctors(); var     query   = from ...; int    x1     = ints1.FirstOrDefault(); int    x2     = ints2.FirstOrDefault(); Doctor doc1   = doctors.FirstOrDefault(doc => doc.City == "Chicago"); Doctor doc2   = doctors.FirstOrDefault(doc => doc.City == "Planet Mars"); var    result = query.FirstOrDefault(); Console.WriteLine(x1);             // 1 Console.WriteLine(x2);             // 0 Console.WriteLine(doc1 == null);   // False Console.WriteLine(doc2 == null);   // True Console.WriteLine(result); 

The sequence can be of any type T; if the sequence is empty, the default value for type T is returned.

See also: First.

6.1.18. Fold

The Fold operator is considered obsolete, see Aggregate.

6.1.19. GroupBy

The GroupBy operator groups the elements of a sequence by key; the keys are yielded by a function applied to each element. Each resulting group is an IEnumerable sequence of elements S with a key K.

 Doctors doctors = new Doctors(); var groups = doctors.GroupBy(doc => doc.City); foreach(var group in groups) {   Console.WriteLine("{0}:", group.Key);   // Chicago, Evanston, ...   foreach(var doc in group)               // {mbl,jl,...}, {ch,cm,...}, ...     Console.WriteLine("  {0}", doc.Initials); } 

A second version allows you to project exactly what data to store in the group, such as only the doctor's initials:

 Doctors doctors = new Doctors(); var groups2 = doctors.GroupBy(doc => doc.City, doc => doc.Initials); foreach(var group in groups2) {   Console.WriteLine("{0}:", group.Key);   // Chicago, Evanston, ...   foreach(var initials in group)          // {mbl,jl,...}, {ch,cm,...}, ...     Console.WriteLine("  {0}", initials); } 

Additional versions allow you to provide a comparer of type IEqualityComparer for comparing keys.

Use of the group by clause in a query expression translates into application of the GroupBy operator. For example, the following statements are equivalent:

 var groups = doctors.GroupBy(doc => doc.City); var groups = from doc in doctors              group doc by doc.City into g              select g; var groups2 = doctors.GroupBy(doc => doc.City, doc => doc.Initials); var groups2 = from doc in doctors               group doc.Initials by doc.City into g               select g; 

See also: OrderBy.

6.1.20. GroupJoin

The GroupJoin operator performs a join of two sequences S1 and S2, based on the keys selected from S1's and S2's elements. The keys are yielded by functions applied to each element; a third function determines the data projected by the join.

Unlike an inner join which yields essentially a table of joined records, the result of a GroupJoin is hierarchical. For each element in S1, there's a possibly empty sub-sequence of matching elements from S2. For example, the following query joins Doctors and Calls via the doctors' initials to determine which doctors are working on what dates:

 DataSets.SchedulingDocs ds = FillDataSet(); var working = ds.Doctors.GroupJoin( ds.Calls,                                     doc => doc.Initials,                                     call => call.Initials,                                     (doc,call) => new { doc.Initials, Calls=call }                                   ); foreach(var record in working) {   Console.WriteLine("{0}:", record.Initials);   foreach(var call in record.Calls)     Console.WriteLine("  {0}", call.DateOfCall); } 

Here's the output:

 ay:   11/2/2006 12:00:00 AM bb: ch: cm: jl:   10/2/2006 12:00:00 AM   11/1/2006 12:00:00 AM . . . 

Use of the join into clause in a query expression translates into application of the GroupJoin operator. For example, the following statements are equivalent:

 var working = ds.Doctors.GroupJoin( ds.Calls,                                     doc => doc.Initials,                                     call => call.Initials,                                     (doc,call) => new { doc.Initials, Calls=call }                                   ); var working = from doc in ds.Doctors               join call in ds.Calls               on doc.Initials equals call.Initials               into j               select new { doc.Initials, Calls = j }; 

To perform a traditional left outer join (and thus flatten the result into a table), use the DefaultIfEmpty operator as follows:

 var working = from doc in ds.Doctors               join call in ds.Calls               on doc.Initials equals call.Initials               into j               from r in j.DefaultIfEmpty()               select new { doc.Initials, Call = r }; foreach(var record in working)   Console.WriteLine("{0}: {1}",     record.Initials,     (record.Call == null) ? "" : record.Call.DateOfCall.ToString()); 

See also: Join.

6.1.21. Intersect

Given two sequences of elements S1 and S2, the Intersect operator returns the distinct elements of S1 that also appear in S2. In other words, Intersect computes the set intersection of S1 and S2.

 int[] intsS1 = { 1, 2, 2, 3, 2, 3, 4, 5, 6, 8 }; int[] intsS2 = { 6, 1, 3, 6, 7 }; var   query1 = from ...; var   query2 = from ...; var commonInts    = intsS1.Intersect(intsS2); var commonResults = query1.Intersect(query2); foreach(var x in commonInts)  // 1, 3, 6   Console.WriteLine(x); foreach(var r in commonResults)   Console.WriteLine(r); 

The sequences may contain elements of any type T. This element type T must be the same at compile-time (e.g. object), but may differ at run-time:

 object[] objects1 = { "abc", "def" }; object[] objects2 = { 1, 2, 3 }; var result = objects1.Intersect(objects2); 

See also: Distinct, Except, and Union.

6.1.22. Join

The Join operator performs an inner equijoin of two sequences S1 and S2, based on the keys selected from S1's and S2's elements. The keys are yielded by functions applied to each element; a third function determines the data projected by the join. For example, the following query joins Doctors and Calls via the doctors' initials to determine which doctors are working on what dates:

 DataSets.SchedulingDocs ds = FillDataSet(); var working = ds.Doctors.Join( ds.Calls,                                doc => doc.Initials,                                call => call.Initials,                                (doc,call) => new { doc.Initials, call.DateOfCall }                               ); foreach(var record in working)   Console.WriteLine(record); 

The query yields pairs of the form (Initials, DateOfCall), created from the joined Doctor and Call elements. Here's the output:

 {Initials=ay, DateOfCall=11/2/2006 12:00:00 AM} {Initials=jl, DateOfCall=10/2/2006 12:00:00 AM} {Initials=jl, DateOfCall=11/1/2006 12:00:00 AM} . . . 

Use of the join clause in a query expression translates into application of the Join operator. For example, the following statements are equivalent:

 var working = ds.Doctors.Join( ds.Calls,                                doc => doc.Initials,                                call => call.Initials,                                (doc,call) => new { doc.Initials, call.DateOfCall }                               ); var working = from doc in ds.Doctors               join call in ds.Calls               on doc.Initials equals call.Initials               select new { doc.Initials, call.DateOfCall }; 

See also: GroupJoin.

6.1.23. Last

The Last operator returns the last element of a sequence; the sequence must be non-empty.

 int[]   ints    = { 1, 2, 3, 4, 5, 6 }; Doctors doctors = new Doctors(); var     query   = from ...; int    last   = ints.Last(); Doctor doctor = doctors.Last(doc => doc.City == "Chicago"); var    result = query.Last(); Console.WriteLine(last);              // 6 Console.WriteLine(doctor.Initials);   // tm Console.WriteLine(result); 

The sequence can be of any type T.

See also: LastOrDefault.

6.1.24. LastOrDefault

The LastOrDefault operator returns the last element of a possibly empty sequence.

 int[]   ints1   = { 1, 2, 3, 4, 5, 6 }; int[]   ints2   = { }; Doctors doctors = new Doctors(); var     query   = from ...; int    x1     = ints1.LastOrDefault(); int    x2     = ints2.LastOrDefault(); Doctor doc1   = doctors.LastOrDefault(doc => doc.City == "Chicago"); Doctor doc2   = doctors.LastOrDefault(doc => doc.City == "Planet Mars"); var    result = query.LastOrDefault(); Console.WriteLine(x1);             // 6 Console.WriteLine(x2);             // 0 Console.WriteLine(doc1 == null);   // False Console.WriteLine(doc2 == null);   // True Console.WriteLine(result); 

The sequence can be of any type T; if the sequence is empty, the default value for type T is returned.

See also: Last.

6.1.25. LongCount

The LongCount operator counts the number of elements in a sequence, yielding a long result. The elements are either the sequence itself, or selected from a sequence of objects.

 int[]      ints   = { 1, 2, 3, 4, 5, 6 }; decimal?[] values = { 1, null, 2, null, 3 }; IEnumerable<Doctor> doctors = new Doctors(); var        query  = from ...; long count1 = ints.LongCount(); long count2 = values.LongCount(); long count3 = doctors.LongCount(); long count4 = doctors.LongCount( doc => doc.City == "Chicago" ); long count  = query.LongCount(); Console.WriteLine(count1);   // 6 Console.WriteLine(count2);   // 5 Console.WriteLine(count3);   // 12 Console.WriteLine(count4);   // 5 Console.WriteLine(count); 

The sequence can be of any type T.

See also: Aggregate, Average, Count, Max, Min, and Sum.

6.1.26. Max

The Max operator finds the maximum of a sequence of values. The values are either the sequence itself, or selected out of a sequence of objects, and must implement IComparable for comparison purposes.

 int[]      ints    = { 1, 2, 3, 6, 5, 4 }; decimal?[] values  = { 1, null, 4, null, 3, 2 }; Doctors    doctors = new Doctors(); var        query   = from ...; int      max1        = ints.Max(); decimal? max2        = values.Max(); string   maxInitials = doctors.Max( doc => doc.Initials ); double   maxYears    = doctors.Max( doc =>                          DateTime.Now.Subtract(doc.StartDate).Days / 365.25 ); var      max         = query.Max(); Console.WriteLine(max1);          // 6 Console.WriteLine(max2);          // 4 Console.WriteLine(maxInitials);   // "vj" Console.WriteLine(maxYears.ToString("0.00"));   // 11.43 Console.WriteLine(max); 

The sequence can be of any type T; the resulting type is the same.

See also: Aggregate, Average, Count, LongCount, Min, and Sum.

6.1.27. Min

The Min operator finds the minimum of a sequence of values. The values are either the sequence itself, or selected out of a sequence of objects, and must implement IComparable for comparison purposes.

 int[]      ints    = { 6, 2, 3, 1, 5, 4 }; decimal?[] values  = { 4, null, 1, null, 3, 2 }; Doctors    doctors = new Doctors(); var        query   = from ...; int      min1        = ints.Min(); decimal? min2        = values.Min(); string   minInitials = doctors.Min( doc => doc.Initials ); double   minYears    = doctors.Min( doc =>                          DateTime.Now.Subtract(doc.StartDate).Days / 365.25 ); var      min         = query.Min(); Console.WriteLine(min1);          // 1 Console.WriteLine(min2);          // 1 Console.WriteLine(minInitials);   // "ay" Console.WriteLine(minYears.ToString("0.00"));   // 0.67 Console.WriteLine(min); 

The sequence can be of any type T; the resulting type is the same.

See also: Aggregate, Average, Count, LongCount, Max, and Sum.

6.1.28. OfType

The OfType operator yields the elements of a sequence that match a given type T. In other words, OfType filters a sequence by type.

               System.Collections.ArrayList  al = new System.Collections.ArrayList();               al.Add(1);               al.Add("abc");               al.Add(2);               al.Add("def");               al.Add(3);               var strings = al.OfType<string>();               foreach(string s in strings)   // "abc", "def"                      Console.WriteLine(s); 

The OfType operator is commonly used to (a) wrap pre-2.0 collections (such as ArrayLists) for use with LINQ and (b) filter mixed collections. Here's a more interesting example of searching a user's Outlook contacts with LINQ:

 Outlook.MAPIFolder folder = this.ActiveExplorer().Session.   GetDefaultFolder( Outlook.OlDefaultFolders.olFolderContacts ); var contacts = from contact in folder.Items.OfType<Outlook.ContactItem>()                where .                      .  // search criteria, e.g. contact.Email1Address != null                      .                select contact; 

See also: Cast.

6.1.29. OrderBy

The OrderBy operator orders a sequence of elements into ascending order; the keys used to order the sequence are yielded by a function applied to each element.

 int[] ints      = {3, 1, 6, 4, 2, 5}; Doctors doctors = new Doctors(); var sorted = ints.OrderBy(x => x); var docs   = doctors.OrderBy(doc => doc.Initials); foreach(var x in sorted)   // 1, 2, 3, 4, 5, 6   Console.WriteLine(x); foreach(var doc in docs)   // ay, bb, ..., vj   Console.WriteLine(doc.Initials); 

A second version allows you to provide a comparer of type IComparer for comparing keys and thus controlling the ordering, e.g., when you want to compare strings in a case-insensitive manner:

 var docs = doctors.OrderBy(doc => doc.Initials,                            StringComparer.CurrentCultureIgnoreCase); 

Use of the orderby clause in a query expression translates into application of the OrderBy operator. For example, the following statements are equivalent:

 var docs = doctors.OrderBy(doc => doc.Initials); var docs = from doc in doctors            orderby doc.Initials            select doc; 

See also: OrderByDescending, ThenBy, and ThenByDescending.

6.1.30. OrderByDescending

The OrderByDescending operator orders a sequence of elements into descending order; the keys used to order the sequence are yielded by a function applied to each element.

 int[] ints      = {3, 1, 6, 4, 2, 5}; Doctors doctors = new Doctors(); var sorted = ints.OrderByDescending(x => x); var docs   = doctors.OrderByDescending(doc => doc.Initials); foreach(var x in sorted)   // 6, 5, 4, 3, 2, 1   Console.WriteLine(x); foreach(var doc in docs)   // vj, tm, ..., ay   Console.WriteLine(doc.Initials); 

A second version allows you to provide a comparer of type IComparer for comparing keys and thus controlling the ordering, e.g., when you want to compare strings in a case-insensitive manner:

 var docs = doctors.OrderByDescending(doc => doc.Initials,                                      StringComparer.CurrentCultureIgnoreCase); 

Use of the orderby clause in a query expression with the descending keyword translates into application of the OrderByDescending operator. For example, the following statements are equivalent:

 var docs = doctors.OrderByDescending(doc => doc.Initials); var docs = from doc in doctors            orderby doc.Initials descending            select doc; 

See also: OrderBy, ThenBy, and ThenByDescending.

6.1.31. Range

The Range operator yields a sequence of integers in the given range, inclusive.

 var oneToTen = System.Query.Sequence.Range(1, 10); foreach(var x in oneToTen)  // 1, 2, 3, ..., 10   Console.WriteLine(x); 

See also: Empty and Repeat.

6.1.32. Repeat

The Repeat operator yields a sequence of values by repeating a given value n times.

 var zeros   = System.Query.Sequence.Repeat(0, 8); var strings = System.Query.Sequence.Repeat("", n); Console.WriteLine(zeros.Count());     // 8 Console.WriteLine(strings.Count());   // n foreach(var zero in zeros)   // 0, 0, ..., 0   Console.WriteLine(zero); 

See also: Empty and Range.

6.1.33. Reverse

The Reverse operator reverses the elements of a sequence.

 int[] ints      = {1, 2, 3, 4, 5, 6}; Doctors doctors = new Doctors(); var revInts = ints.Reverse(); var docs    = from doc in doctors               orderby doc.Initials               select doc; var revDocs = docs.Reverse(); foreach(var x in revInts)     // 6, 5, 4, 3, 2, 1   Console.WriteLine(x); foreach(var doc in revDocs)   // vj, tm, ..., ay   Console.WriteLine(doc.Initials); 

See also: OrderBy and OrderByDescending.

6.1.34. Select

The Select operator applies a projection function over a sequence of elements, yielding a sequence of possibly new elements.

 int[] ints      = {1, 2, 3, 4, 5, 6}; Doctors doctors = new Doctors(); var sameInts = ints.Select(x => x); var chicago  = doctors.Where(d => d.City == "Chicago").Select(d => d.Initials); var names    = doctors.Select(d => new {LN=d.FamilyLastName, FN=d.GivenFirstName}); foreach(var x in sameInts)   // 1, 2, 3, 4, 5, 6   Console.WriteLine(x); foreach(var d in chicago)    // mbl, jl, kl, py, tm   Console.WriteLine(d); foreach(var n in names)      // {LN=Larsen, FN=Marybeth}, ...   Console.WriteLine(n); 

Use of the select clause in a query expression translates into application of the Select operator (except in trivial cases where the Select operator can be optimized away). For example, the following statements are equivalent:

 var chicago = doctors.Where(d => d.City == "Chicago").Select(d => d.Initials); var chicago = from d in doctors               where d.City == "Chicago"               select d.Initials; 

A second version of the Select operator provides an element's 0-based index in the sequence along with the element itself, for example:

 var sumLast3 = ints.Select( (x,index) => (index >= ints.Length-3) ? x : 0 ).Sum(); Console.WriteLine(sumLast3);   // 15 

See also: SelectMany and Where.

6.1.35. SelectMany

The SelectMany operator applies a projection function over a sequence of sequences, yielding a "flattened" sequence of possibly new elements. For example, turning an array of arrays into an array:

 List<int[]> list = new List<int[]>(); int[] ints123 = {1, 2, 3}; int[] ints456 = {4, 5, 6}; list.Add(ints123); list.Add(ints456); var flat = list.SelectMany(x => x); foreach (var x in list)   // Int32[], Int32[]   Console.WriteLine(x); foreach (var x in flat)   // 1, 2, 3, 4, 5, 6   Console.WriteLine(x); 

The SelectMany operator is commonly used to flatten hierarchical data. For example, the following query yields the list of doctors working in October 2006, with sub-lists of the calls each is working:

 DataSets.SchedulingDocs ds = FillDataSet(); var oct2006 = from d in ds.Doctors                join c in ds.Calls                on d.Initials equals c.Initials                where c.DateOfCall >= new DateTime(2006, 10, 1) &&                      c.DateOfCall <= new DateTime(2006, 10, 31)                group c by d.Initials into g                select g; foreach (var group in oct2006)  // jl: 1, mbl: 2 {   Console.WriteLine("{0}: {1}", group.Key, group.Count());   foreach (var call in group)     Console.WriteLine(call.DateOfCall); } 

To flatten the hierarchy into just the list of calls:

 var calls = oct2006.SelectMany(call => call); foreach (var c in calls)   Console.WriteLine(c.DateOfCall); 

Use of the select clause in a query expression on all but the initial from clause translates into application of the SelectMany operator. For example, here's another way to flatten the list of calls for doctors working in October 2006:

 var calls = from d in ds.Doctors                  from c in ds.Calls                  where                    d.Initials == c.Initials &&                    c.DateOfCall >= new DateTime(2006, 10, 1) &&                    c.DateOfCall <= new DateTime(2006, 10, 31)                  select c; 

This is translated into the following application of the SelectMany operator:

 var calls = ds.Doctors.SelectMany(                d => ds.Calls.Where(c => d.Initials == c.Initials &&                                    c.DateOfCall >= new DateTime(2006, 10, 1) &&                                    c.DateOfCall <= new DateTime(2006, 10, 31))); 

A second version of the SelectMany operator provides an element's 0-based index in the outer sequence along with the element itself.

See also: Select and Where.

6.1.36. Single

The Single operator returns the lone element of a sequence; the sequence must contain exactly one element.

 int[]   ints    = { 3 }; Doctors doctors = new Doctors(); var     query   = from ...; int    lone   = ints.Single(); Doctor doctor = doctors.Single(doc => doc.Initials == "mbl"); var    result = query.Single(); Console.WriteLine(lone);                 // 3 Console.WriteLine(doctor.PagerNumber);   // 52248 Console.WriteLine(result); 

The sequence can be of any type T.

See also: SingleOrDefault.

6.1.37. SingleOrDefault

The SingleOrDefault operator returns the lone element of a sequence; the sequence must be empty or contain exactly one element.

 int[]   ints1   = { 3 }; int[]   ints2   = { }; Doctors doctors = new Doctors(); var     query   = from ...; int    x1     = ints1.SingleOrDefault(); int    x2     = ints2.SingleOrDefault(); Doctor doc1   = doctors.SingleOrDefault(doc => doc.Initials == "mbl"); Doctor doc2   = doctors.SingleOrDefault(doc => doc.Initials == "AAA"); var    result = query.SingleOrDefault(); Console.WriteLine(x1);             // 3 Console.WriteLine(x2);             // 0 Console.WriteLine(doc1 == null);   // False Console.WriteLine(doc2 == null);   // True Console.WriteLine(result); 

The sequence can be of any type T; if the sequence is empty, the default value for type T is returned.

See also: Single.

6.1.38. Skip

The Skip operator skips the first n elements of a sequence, yielding the remaining elements. If n <= 0 the result is the sequence itself; if n >= sequence's length the result is an empty sequence.

 int[] ints  = { 1, 2, 3, 4, 5, 6 }; var   query = from ...; var last3    = ints.Skip(3); var bottom10 = query.Skip( query.Count() - 10 ); foreach(var x in last3)  // 4, 5, 6   Console.WriteLine(x); foreach(var r in bottom10)   Console.WriteLine(r); 

The sequence can be of any type T.

See also: Take.

6.1.39. SkipWhile

Given a function F and a sequence S, the SkipWhile operator skips the first n elements of S where F returns true, yielding the remaining elements. Two versions of F are supported: accepting an element, or accepting an element along with its 0-based index in the sequence.

 int[] ints  = { 1, 2, 3, 4, 5, 6 }; var   query = from ...; var all   = ints.SkipWhile(x => false); var none  = ints.SkipWhile(x => true); var last3 = ints.SkipWhile( (x,i) => i < 3 ); var lastN = query.SkipWhile(result => ...); foreach(var x in all)     // 1, 2, 3, 4, 5, 6   Console.WriteLine(x); foreach(var x in none)    // <none>   Console.WriteLine(x); foreach(var x in last3)   // 4, 5, 6   Console.WriteLine(x); foreach(var r in lastN)   Console.WriteLine(r); 

The sequence can be of any type T.

See also: TakeWhile and Where.

6.1.40. Sum

The Sum operator computes the sum of a sequence of numeric values. The values are either the sequence itself or selected out of a sequence of objects.

 int[]      ints    = { 1, 2, 3, 4, 5, 6 }; decimal?[] values  = { 1, null, 2, null, 3, 4 }; Doctors    doctors = new Doctors(); var        query   = from ...; int      sum1     = ints.Sum(); decimal? sum2     = values.Sum(); double   sumYears = doctors.Sum( doc =>                       DateTime.Now.Subtract(doc.StartDate).Days / 365.25 ); var      sum      = query.Sum(); Console.WriteLine(sum1);   // 21 Console.WriteLine(sum2);   // 10 Console.WriteLine(sumYears.ToString("0.00"));   // 68.61 Console.WriteLine(sum); 

The values can be of type int, int?, long, long?, decimal, decimal?, double, or double?. The resulting type is the same.

See also: Aggregate, Average, Count, LongCount, Max, and Min.

6.1.41. Take

The Take operator yields the first n elements of a sequence. If n <= 0 the result is an empty sequence; if n >= sequence's length the result is the sequence itself.

 int[] ints  = { 1, 2, 3, 4, 5, 6 }; var   query = from ...; var first3 = ints.Take(3); var top10  = query.Take(10); foreach(var x in first3)  // 1, 2, 3   Console.WriteLine(x); foreach(var r in top10)   Console.WriteLine(r); 

The sequence can be of any type T.

See also: Skip.

6.1.42. TakeWhile

Given a function F and a sequence S, the TakeWhile operator yields the first n elements of S where F returns true. Two versions of F are supported: accepting an element, or accepting an element along with its 0-based index in the sequence.

 int[] ints  = { 1, 2, 3, 4, 5, 6 }; var   query = from ...; var all    = ints.TakeWhile(x => true); var none   = ints.TakeWhile(x => false); var first3 = ints.TakeWhile( (x,i) => i < 3 ); var firstN = query.TakeWhile(result => ...); foreach(var x in all)      // 1, 2, 3, 4, 5, 6   Console.WriteLine(x); foreach(var x in none)     // <none>   Console.WriteLine(x); foreach(var x in first3)   // 1, 2, 3   Console.WriteLine(x); foreach(var r in firstN)   Console.WriteLine(r); 

The sequence can be of any type T.

See also: SkipWhile and Where.

6.1.43. ThenBy

The ThenBy operator takes an ordered sequence and yields a secondary, ascending ordering; the keys used for the secondary ordering are yielded by a function applied to each element. Ordered sequences are typically produced by OrderBy or OrderByDescending, but can also be produced by ThenBy and ThenByDescending to yield additional sub-orderings.

 Doctors doctors = new Doctors(); var docs = doctors.OrderBy(doc => doc.City).ThenBy(doc => doc.Initials); foreach(var doc in docs)   Console.WriteLine("{0}: {1}", doc.City, doc.Initials); 

A second version allows you to provide a comparer of type IComparer for comparing keys and thus controlling the ordering, e.g., when you want to compare strings in a case-insensitive manner:

 var docs = doctors.OrderBy(doc => doc.City)                   .ThenBy(doc => doc.Initials,                           StringComparer.CurrentCultureIgnoreCase); 

Use of an orderby clause in a query expression with subsequent keys translates into application of the ThenBy operator. For example, the following are equivalent:

 var docs = doctors.OrderBy(doc => doc.City).ThenBy(doc => doc.Initials); var docs = from doc in doctors            orderby doc.City, doc.Initials            select doc; 

See also: OrderBy, OrderByDescending, and ThenByDescending.

6.1.44. ThenByDescending

The ThenByDescending operator takes an ordered sequence and yields a secondary, descending ordering; the keys used for the secondary ordering are yielded by a function applied to each element. Ordered sequences are typically produced by OrderBy or OrderByDescending, but can also be produced by ThenBy and ThenByDescending to yield additional sub-orderings.

 Doctors doctors = new Doctors(); var docs = doctors.OrderBy(doc => doc.City).ThenByDescending(doc => doc.Initials); foreach(var doc in docs)   Console.WriteLine("{0}: {1}", doc.City, doc.Initials); 

A second version allows you to provide a comparer of type IComparer for comparing keys and thus controlling the ordering, e.g., when you want to compare strings in a case-insensitive manner:

 var docs = doctors.OrderBy(doc => doc.City)                   .ThenByDescending(doc => doc.Initials,                                     StringComparer.CurrentCultureIgnoreCase); 

Use of an orderby clause in a query expression with subsequent keys and the descending keyword translates into application of the ThenBy operator. For example, the following are equivalent:

 var docs = doctors.OrderBy(doc => doc.City).ThenByDescending(doc => doc.Initials); var docs = from doc in doctors            orderby doc.City, doc.Initials descending            select doc; 

See also: OrderBy, OrderByDescending, and ThenBy.

6.1.45. ToArray

The ToArray operator iterates across a sequence of values, yielding an array containing these values. For example, doctors living in Chicago:

 Doctors doctors = new Doctors(); var query = from doc in doctors             where doc.City == "Chicago"             select doc; Doctor[] chicago = query.ToArray(); 

Since queries are lazily evaluated, ToArray is commonly used to execute a query and capture the results in a simple data structure.

See also: ToDictionary, ToList, ToLookup, and ToSequence.

6.1.46. ToDictionary

The ToDictionary operator iterates across a sequence of values, yielding a Dictionary<K, V> of (key, value) pairs. Each key must be unique, resulting in a one-to-one mapping of key to value. For example, storing doctors by their initials:

 Doctors doctors = new Doctors(); var query = from doc in doctors             where doc.City == "Chicago"             select doc; Dictionary<string, Doctor> chicago = query.ToDictionary(doc => doc.Initials); foreach(var pair in chicago)   Console.WriteLine("{0}: {1}", pair.Key, pair.Value.PagerNumber); 

Since queries are lazily evaluated, ToDictionary is commonly used to execute a query and capture the results in a data structure that supports efficient lookup by key. For example, finding a doctor via their initials:

 Doctor mbl = chicago["mbl"]; 

Another version provides control over exactly what values are stored in the data structure, e.g., only the doctor's email address:

 Dictionary<string, string> emails = doctors.ToDictionary(doc => doc.Initials,                                                          doc => doc.EmailAddress); 

Finally, additional versions of ToDictionary allow you to provide a comparer of type IEqualityComparer for comparing keys.

See also: ToArray, ToList, ToLookup, and ToSequence.

6.1.47. ToList

The ToList operator iterates across a sequence of values, yielding a List<T> containing these values. For example, doctors living in Chicago:

 Doctors doctors = new Doctors(); var query = from doc in doctors             where doc.City == "Chicago"             select doc; List<Doctor> chicago = query.ToList(); 

Since queries are lazily evaluated, ToList is commonly used to execute a query and capture the results in a flexible data structure.

See also: ToArray, ToDictionary, ToLookup, and ToSequence.

6.1.48. ToLookup

The ToLookup operator iterates across a sequence of values, yielding a Lookup<K, V> of (key, value) pairs. The keys do not need to be unique; values with the same key form a collection under that key, resulting in a one-to-many mapping of key to values. For example, grouping doctors by city:

 Doctors doctors = new Doctors(); var query = from doc in doctors             select doc; Lookup<string, Doctor> cities = query.ToLookup(doc => doc.City); foreach(var pair in cities) {   Console.WriteLine("{0}:", pair.Key);  // city   foreach(var doc in pair)              // doctors in that city     Console.WriteLine("  {0}", doc.Initials); } 

Since queries are lazily evaluated, ToLookup is commonly used to execute a query and capture the results in a data structure that supports efficient lookup by key. For example, finding the doctors living in Chicago:

 IEnumerable<Doctor> docs = cities["Chicago"]; 

Another version provides control over exactly what values are stored in the data structure, e.g., only the doctor's initials:

 Lookup<string, string> cities = doctors.ToLookup(doc => doc.City,                                                  doc => doc.Initials); 

Finally, additional versions of ToLookup allow you to provide a comparer of type IEqualityComparer for comparing keys.

See also: ToArray, ToDictionary, ToList, and ToSequence.

6.1.49. ToSequence

The ToSequence operator casts a sequence as a sequence, thereby hiding any public members of the original sequencein particular those that might conflict or compete with the standard query operators. Use this operator when you want to gain access to the standard LINQ query operators.

For example, the following use of the Count query operator fails to compile:

 Doctors doctors = new Doctors(); int count = doctors.Count(doc => doc.City == "Chicago");  // ERROR! 

It fails because the Doctors class provides a conflicting Count property (inherited from List<T>). The ToSequence operator provides a quick solution:

 int count1 = doctors.Count; int count2 = doctors.ToSequence().Count(); int count3 = doctors.ToSequence().Count( doc => doc.City == "Chicago" ); Console.WriteLine(count1);   // 12 Console.WriteLine(count2);   // 12 Console.WriteLine(count3);   // 5 

See also: ToArray, ToDictionary, ToList, and ToLookup.

6.1.50. Union

Given two sequences of elements S1 and S2, the Union operator returns the distinct elements of S1, followed by the distinct elements of S2 not in S1. In other words, Union computes the set union of S1 and S2.

 int[] intsS1 = { 1, 2, 2, 3, 2, 3, 4, 6 }; int[] intsS2 = { 6, 1, 3, 5 }; var   query1 = from ...; var   query2 = from ...; var allInts    = intsS1.Union(intsS2); var allResults = query1.Union(query2); foreach(var x in allInts)  // 1, 2, 3, 4, 6, 5   Console.WriteLine(x); foreach(var r in allResults)   Console.WriteLine(r); 

The sequences may contain elements of any type T. This element type T must be the same at compile-time (e.g. object), but may differ at run-time:

 object[] objects1 = { "abc", "def" }; object[] objects2 = { 1, 2, 3 }; var result = objects1.Union(objects2); 

See also: Distinct, Except, and Intersect.

6.1.51. Where

The Where operator applies a function to a sequence of elements, yielding a sub-sequence of these elements.

 int[] ints = {1, 2, 3, 4, 5, 6}; Doctors doctors = new Doctors(); var even    = ints.Where( x => x % 2 == 0); var chicago = doctors.Where( doc => doc.City == "Chicago" ); foreach(var x in even)      // 2, 4, 6   Console.WriteLine(x); foreach(var doc in chicago)   // mbl, jl, kl, py, tm   Console.WriteLine(doc.Initials); 

Use of the where clause in a query expression translates into application of the Where operator. For example, the following statements are equivalent:

 var chicago = doctors.Where( doc => doc.City == "Chicago" ); var chicago = from doc in doctors               where doc.City == "Chicago"               select doc; 

A second version of the Where operator provides an element's 0-based index in the sequence along with the element itself, for example:

 var last3 = ints.Where( (x,index) => (index >= ints.Length-3) ? true : false ); foreach (var x in last3)   // 4, 5, 6   Console.WriteLine(x); 

See also: Select.

NOTE

The application of LINQ is limited only by your imagination (and time ). Here are a couple of the more interesting LINQ extensions floating around on the Web:

  1. BLinq is a tool that generates an ASP.NET web application from a database schema. The web site supports the display, creation, and manipulation of the data in the database. LINQ to SQL is used for all database access, making the generated code easier to understand and modify. For more information see http://www.asp.net/sandbox/app_blinq.aspx?tabid=62.

  2. LINQ to Amazon extends LINQ to support the querying of Amazon.com. See http://weblogs.asp.net/fmarguerie/archive/2006/06/26/Introducing-Linq-to-Amazon.aspx (http://weblogs.asp.net/fmarguerie/archive/2006/06/26/Introducing-Linq-to-Amazon.aspx:).



LINQ[c] The Future of Data Access in C# 3. 0
LINQ[c] The Future of Data Access in C# 3. 0
ISBN: N/A
EAN: N/A
Year: 2006
Pages: 25

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net