6.1.6.1.1. AggregateThe 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.
6.1.2. AllThe 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. AnyThe 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. AverageThe 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. CastThe 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. ConcatThe 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. ContainsThe 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. CountThe 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. DefaultIfEmptyGiven 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. DistinctGiven 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. ElementAtThe 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. ElementAtOrDefaultThe 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. EmptyThe 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. EqualAllThe 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. ExceptGiven 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. FirstThe 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. FirstOrDefaultThe 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. FoldThe Fold operator is considered obsolete, see Aggregate. 6.1.19. GroupByThe 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. GroupJoinThe 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. IntersectGiven 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. JoinThe 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. LastThe 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. LastOrDefaultThe 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. LongCountThe 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. MaxThe 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. MinThe 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. OfTypeThe 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. OrderByThe 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. OrderByDescendingThe 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. RangeThe 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. RepeatThe 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. ReverseThe 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. SelectThe 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. SelectManyThe 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. SingleThe 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. SingleOrDefaultThe 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. SkipThe 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. SkipWhileGiven 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. SumThe 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. TakeThe 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. TakeWhileGiven 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. ThenByThe 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. ThenByDescendingThe 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. ToArrayThe 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. ToDictionaryThe 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. ToListThe 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. ToLookupThe 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. ToSequenceThe 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. UnionGiven 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. WhereThe 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:
|