Last Updated: June 24, 2008.
LINQ, Language Integrated Query, is a great new feature of C# 3.0. This page gives a small overview of LINQ. Before we start with LINQ we have to understand some new features of C# 3.0 that were added so LINQ could work.
- New Features in C# 3.0
- Lambda Expressions
Lambda expressions are a list of inputs, the "=>" symbol, and an expression body.
x => x * 0.05
We can make using delegates shorter by using a lambda expression:
// CalculateTax is a delegate that takes a double and returns a double public delegate double CalculateTax(double x); static void Main(string[] args) { CalculateTax stateDelegate = x => x * 0.05; CalculateTax federalDelegate = x => { if (x > 1000.0) return x * 0.02; else return 0.0; }; double amountOfPurchase = 12.99; Console.WriteLine("{0}", stateDelegate(amountOfPurchase)); Console.WriteLine("{0}", federalDelegate(amountOfPurchase)); Console.In.ReadLine(); }When using more than one input variable, surround the input with parenthesis and separate with commas.
using System; namespace PlayingAround { class Lambda { public delegate int Largest(int x, int y); public static Largest myLargest = (int x, int y) => { return x > y ? x : y; }; private static void Main() { Console.Out.WriteLine("myLargest(4,5) = " + myLargest(4,5)); //prints 5 Console.Out.Write("press return to exit."); Console.In.ReadLine(); } } }Although these examples are painfully contrived, the common use of lambdas are in LINQ being used as anonyous delegates.
- Extension Methods
In C#3.0 one of the very cool concepts is "Open Classes" where you can add methods to existing classes. In C# parlance this is an extension method. Below is an example of adding a new method to our old friend "string".
using System; namespace PlayingAround { public static class MyStringExtensionClass { //wraps an xml tag around a string public static string Wrap(this string s, string tag) { return "<" + tag + ">" + s + "</" + tag + ">"; } } class TestMe { static void Main(string[] args) { Console.WriteLine("Warning".Wrap("h1")); // <h1>Warning</h1> Console.In.ReadLine(); } } } - Automatic Properties
In the old days before c# 3.0 you had to manually create the hidden variable behind fields:
using System; using System.Collections.Generic; public class Book { private string _author; private string _title; public string Author { get{return _author;} set{_author = value;} } public string Title { get{return _title;} set{_title = value;} } public static void Main() { Book myBook = new Book(); myBook.Title = "Gates of Fire"; myBook.Author = "Stephen Pressfield"; Console.In.ReadLine(); } }With Automatic Properties, the compiler will generate a private field for you. You can change this later if you need to do something more elegant than just get the private field's value.
using System; using System.Collections.Generic; public class Book { public string Author { get; set; } public string Title { get; set; } public static void Main() { Book myBook = new Book(); myBook.Title = "Gates of Fire"; myBook.Author = "Stephen Pressfield"; Console.WriteLine(myBook.Title); Console.In.ReadLine(); } } - Local Variable Type Inference
The compiler can infer the type of a variable from the expression on the right side. These are useful in LINQ expressions when the types can be overwhelming to enter, trust me. The type can be something like a function that takes a function with two ints and a float, and another function that takes a string and returns a function that takes two ints and a function that...
It is important to remember that this is not a type-less variable, the complier just infers and checks it at compile time.
var i = 6; //trivial example, not really used in practice with ints Console.Out.WriteLine("i=" + i); - Object Initialization in C# 3.0
Objects can now be initialized in a more concise manner as shown below:
... public class House { public double price; public int stories; public string exterior; } class TestMe { static void Main(string[] args) { //old style House myOldHouse = new House(); myOldHouse.price = 200000.00; myOldHouse.stories = 1; myOldHouse.exterior = "wood"; //new style House myNewHouse = new House { price = 250000.00, stories = 2, exterior = "brick" }; Console.In.ReadLine(); } } - Anonymous Types
We can create anonymous types. The compiler will give our creation a hidden name.
var animal = new { IsMammal = true , Name = "lion" }; Console.Out.WriteLine("Name=" + animal.Name); Console.Out.WriteLine("is mammal? " + animal.IsMammal); - Collection Initializers
Instead of the klunky:
ArrayList ab = new ArrayList(); ab.Add("a"); ab.Add("b");Using the collection initializer we can write
ArrayList ab = new ArrayList {"a", "b"}; - Aggregation
Aggregators are extension methods that act on IEnumerable<T>
int[] ints = { 1, 3, 5, 7 }; Console.WriteLine(ints.Sum()); // 16 Console.WriteLine(ints.Min()); // 1 Console.WriteLine(ints.Max()); // 7 Console.WriteLine(ints.Average()); // 4 - Expression Trees
This is a new feature in C# 3.0, which is not used by a typical developer, but are used by creators of LINQ-enabled storage devices.
- Partial Functions
Partial functions allow class designers to put in hooks for future use. If the functions are never given substance, the compiler ignores them.
using System; namespace PlayingAround { public partial class MyTest { partial void myPreHook();//never given substance, ignored by compiler public MyTest() { myPreHook(); Console.Out.WriteLine("Creating MyTest."); } public static void Main() { MyTest myTest = new MyTest(); Console.Out.Write("press return to exit."); Console.In.ReadLine(); } } }Adding a definition for myPreHook() will cause the compiler to generate the code and it will be executed.
public partial class MyTest { partial void myPreHook() { Console.Out.WriteLine("myPreHook."); } }
- Lambda Expressions
- LINQ - Language Integrated Query
LINQ is designed to work with any storage medium, e.g., SQL, XML, DataSets, or objects.
LINQ has two syntaxes: query expression which is kinda SQL-like or standard dot notation which is standard c# . I prefer the dot notation since it really shows what is happening and it works with all query operators.
Make sure you have a reference to "System.data.Linq.dll" in your solution.
Below is an example using some of the LINQ features for in-memory objects. LINQ enables VStudio to give intelliSense to some queries. For in-memory LINQ, it's all about using the Standard Query Operators. These are extension methods on the IEnumerable<T> class, methods like "Where()","Select()","Sum()" and "Average()".
- Example using Standard Query Operators
This shows the use of the Where(), OrderBy(), Count(), Sum(), Min(), Select(), and ForEach() methods.
using System; using System.Collections.Generic; using System.Linq; namespace PlayingAround { internal class Photo { public Photo(string photographer, string subject, int year, double cost) { this.photographer = photographer; this.subject = subject; this.year = year; this.cost = cost; } public string photographer { get; set; } public string subject { get; set; } public int year { get; set; } public double cost { get; set; } public override string ToString() { return photographer + ", " + subject + ", " + year + ", " + cost; } } internal class PhotoLab { private static void Main(string[] args) { List<Photo> list = new List<Photo> { new Photo("Frank", "Cats", 2002, 1.10), new Photo("Lee", "Dogs and Cats", 2003, 2.05), new Photo("Sarah", "Stingrays", 2007, 23.00), new Photo("Jon", "Meerkats", 2005, 16.75) }; //simple where clause var oldPhotos = list.Where(p => p.year == 2003); Console.Out.WriteLine("oldPhotos.Count() = {0}", oldPhotos.Count()); // 1 //Order Operators //use OrderBy extension operator to sort oldPhotos = list.OrderBy(p => p.year); //2002, 2003, 2005, 2007 foreach (var photo in oldPhotos) { Console.Out.WriteLine("photo = {0}", photo); } oldPhotos = list.OrderByDescending(p => p.year); //2007, 2005, 2003, 2002 foreach (var photo in oldPhotos) { Console.Out.WriteLine("photo = {0}", photo); } //Aggregate Operators var number = list.Count(p => p.year > 2003); //sums the length of all the photographer's names. Did I mention this is a contrived example? number = list.Sum(p => p.photographer.Length); Console.Out.WriteLine("number = {0}", number); //16 //find shortest subject length number = list.Min(p => p.subject.Length); Console.Out.WriteLine("number = {0}", number); //4 //using "Select" to create new anonymous classes var photos = list.Where(p => p.year < 2005).Select(p => new {p.photographer, p.year}); foreach (var photo in photos) { Console.Out.WriteLine("photo = {0}", photo); //photo = { photographer = Frank, year = 2002 }... } //write all photos to console list.ForEach(p => Console.WriteLine(p)); //same as above but more concise, and a little spooky list.ForEach(Console.WriteLine); Console.In.ReadLine(); } } } - Create your own LINQ Query Operators
Below is an example of extending the IEnumerable<T> class to include an operator that returns a List<T> of every other item.
using System; using System.Collections.Generic; namespace PlayingAround { class EveryOtherExample { private static void Main() { List<int> ints = new List<int>{0, 1, 2, 3, 4, 5, 6}; ints.ForEach(i => Console.Out.Write(i)); List<int> everyOther = ints.EveryOther(); //call our new Query Operator everyOther.ForEach(i => Console.Out.Write(i));// writes 0246 Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } // let's create our own (non)Standard Query Operator /// <summary> /// returns every other item starting with the first item /// </summary> public static class MyEveryOtherExtensionMethod { public static List<T> EveryOther<T>(this IEnumerable<T> source) { List<T> list = new List<T>(); bool shouldIAddIt = true; foreach (var variable in source) { if(shouldIAddIt) {list.Add(variable);} //add every other one shouldIAddIt = !shouldIAddIt; } return list; } } } - Deferred Queries
Many of the standard query operators do not execute immediately, but wait until needed. In the example below "abc.Intersect(cdef)" is not executed until needed for printing. It is re-evaluted when needed again.
using System; using System.Collections; using System.Collections.Generic; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { class Deferred { private static void Main() { List<string> abc = new List<string> { "a", "b", "c" }; List<string> cdef = new List<string> { "c","d","e","f"}; IEnumerable intersection = abc.Intersect(cdef); //deferred execution cdef[3] = "a"; foreach (var letter in intersection) //now the IEnumerable intersection is done { Console.Out.WriteLine("letter = " + letter); //writes a,c } cdef[2] = "b"; //Getting the Enumerator for "intersection" forces it to start to reconstruct the list again foreach (var letter in intersection) { Console.Out.WriteLine("letter = " + letter); //writes a,b,c } Console.Out.Write("press return to exit."); Console.In.ReadLine(); } } } - Explicit Interfaces
Sometimes different interfaces have the same method signatures. To specify a specific interface, preface the method with the name of the interface followed by a ".". When calling the method, the object must be cast as that interface type.
using System; namespace PlayingAround { class ExplicitInterface { interface IFlute { void Play(); } interface IGuitar { void Play(); } class Musician : IFlute, IGuitar { void IFlute.Play() { Console.WriteLine("Playing Flute"); } void IGuitar.Play() { Console.WriteLine("Playing Guitar"); } } public static void Main(string[] args) { Console.WriteLine("hello"); Musician muscian = new Musician(); //muscian.Play(); error //with Explicit Interfaces you must declare which interface is being called ((IFlute)muscian).Play(); Console.ReadLine(); } } } - Creating an Xml document with Linq
(namespace omitted for clarity)
using System; using System.Xml.Linq; namespace PlayingAround { /// <summary> /// creates an xml document with nested elements /// </summary> class XmlCreate { private static void Main() { XElement books = new XElement("books", new XElement("book", new XAttribute("title","Peopleware"), new XElement("author","DeMarco and Lister")), new XElement("book", new XAttribute("title", "Agile and Iterative Development"), new XElement("author", "Craig Larman"))); Console.Out.WriteLine("books.ToString() = \r\n" + books); Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } }Produces:
books.ToString() = <books> <book title="Peopleware"> <author>DeMarco and Lister</author> </book> <book title="Agile and Iterative Development"> <author>Craig Larman</author> </book> </books> press return to exit. - Using LINQ to search xml files
We use "var" as the type of "demarco_books" becasue the real type reported by "GetType()" is quite a mouthful, "demarco_books.GetType() = System.Linq.Enumerable+<WhereIterator>d__0`1[System.Xml.Linq.XElement]
using System; using System.IO; using System.Linq; using System.Xml.Linq; namespace PlayingAround { class LinqXml { private static void Main() { XElement books = XElement.Parse(File.ReadAllText(@"..\..\books.xml")); IEnumerable<XElement> demarco_books = books.Elements("book").Where(book => book.Element("author").ToString().Contains("DeMarco")); demarco_books.ToList().ForEach(b => Console.Out.WriteLine("DeMarco books: " + b.Attribute("title"))); Console.Out.Write("done."); Console.In.ReadLine(); } } }Given this xml file
<books> <book title="Peopleware"> <author>DeMarco and Lister</author> </book> <book title="Agile and Iterative Development"> <author>Craig Larman</author> </book> <book title="Design Patterns"> <author>Gamma, Helm, Johnson, Blissides</author> </book> <book title="Software Creativity 2.0"> <author>Robert L Glass and Tom DeMarco</author> </book> </books>The program produces:
DeMarco books: title="Peopleware" DeMarco books: title="Software Creativity 2.0" done.
- Using LINQ to sort objects
using System; using System.Linq; namespace PlayingAround { class LinqArray { private static void Main() { string[] presidents = {"Washington", "Madison", "Lincoln"}; //let's sort the array var sorted = presidents.OrderBy(p => p); sorted.ToList().ForEach(p => Console.Out.WriteLine(p)); Console.Out.Write("press return to exit."); Console.In.ReadLine(); } } } - Using Legacy Collections
C# offers a few ways to use older collections like ArrayList with LINQ. Cast() will try to cast all elements to the desired generic type. In the example below Cast() is successful in casting "12" to a string, so the number of elements is 5. OfType() will pluck out of the original Arraylist all the correct types, so its count is only 4. If we uncomment the line adding "new object()", which cannot be cast to a string, the Cast() method will throw an InvalidCastException, but the OfType() method will just ignore it.
Some people will recommend using OfType() because it will not throw an exception when encountering an unexpected type of object. I usually prefer Cast() because I want to know up front during testing if any odd type has wandered into my collection. The only time to use OfType() is when you really expect to find mixed object types in your collection.
using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace PlayingAround { class Legacy { private static void Main() { ArrayList arrayList = new ArrayList(); arrayList.Add("up"); arrayList.Add("down"); arrayList.Add("charm"); arrayList.Add("strange"); arrayList.Add(12); //arrayList.Add(new object()); //will cause exception in Cast() IEnumerable<string> quarks = arrayList.Cast<string>().OrderByDescending(q => q); Console.Out.WriteLine("Number of elements = " + quarks.Count()); //5 quarks = arrayList.OfType<string>().OrderByDescending(q => q); Console.Out.WriteLine("Number of elements = " + quarks.Count()); //4 Console.Out.Write("press return to exit."); Console.In.ReadLine(); } } } - Projection
Projection takes a series of one type of object and creates a series of another type.
using System; using System.Collections.Generic; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { public class Book { public string author; public string title; public string rating; } class Projection { private static void Main() { List<Book> books = new List<Book> { new Book {author = "Demarco", title = "PeopleWare", rating = "Good"}, new Book {author="Tolkien", title="The Hobbit", rating="Super"}, new Book {author="Pressfield", title="Gates of Fire", rating="Super"} }; //authorAndTitle has some machine-generated mangled type name var authorAndTitle = books.Select(b => new {b.author, b.title}); //projection authorAndTitle.ToList().ForEach(Console.WriteLine); /* prints: { author = Demarco, title = PeopleWare } { author = Tolkien, title = The Hobbit } { author = Pressfield, title = Gates of Fire } */ Console.Out.WriteLine("authorAndTitle type = " + authorAndTitle.GetType()); /* prints "authorAndTitle type = System.Linq.Enumerable+<SelectIterator>d__d`2[PlayingAround.Book,<>f__AnonymousType1`2[System.String,System.String]]" */ Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } } - Partioning Functions
Take(), TakeWhile(), Skip(), and SkipWhile()
using System; using System.Collections.Generic; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { class TakeWhile { private static void Main() { int[] numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8}; //Take simply returns the first n elements IEnumerable<int> three = numbers.Take(3); three.ToList().ForEach(n => Console.Write(n)); //writes: 012 //TakeWhile returns elements until one of them is false and then stops IEnumerable<int> odds = numbers.TakeWhile(n => n < 5); odds.ToList().ForEach(n => Console.Write(n)); //writes: 01234 IEnumerable<int> skipFive = numbers.Skip(5); //skips first five skipFive.ToList().ForEach(n => Console.Write(n)); //writes: 5678 Console.WriteLine(); IEnumerable<int> skipWhileLessThanFour = numbers.SkipWhile(n => n < 4); skipWhileLessThanFour.ToList().ForEach(n => Console.Write(n)); //writes: 45678 Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } } - Concatenation
the Concat() method joins lists
using System; using System.Collections; using System.Collections.Generic; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { class Concat { private static void Main() { int[] little = { 0, 1, 2, 3, 4 }; int[] big = { 5, 6, 7, 8 }; IEnumerable<int> all = little.Concat(big); all.ToList().ForEach(n => Console.Write(n)); //writes: 012345678 Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } } - Sorting
OrderBy(),ThenBy()
using System; using System.Collections; using System.Collections.Generic; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { class Order { public class Employee { public string last; public string first; public double salary; public Employee(string last, string first, double salary) { this.last = last; this.first = first; this.salary = salary; } override public string ToString() {return string.Format("{0}, {1}: ${2}", last, first, salary);}} public static void Main() { Employee[] employees = { new Employee("Jones", "Sara", 11000.00), new Employee("Jones", "Brad", 10000.00), new Employee("Aaron", "Mike", 10000.00), new Employee("Xader", "Xena", 20000.00) }; Print("No ordering", employees); Print("Order by last", employees.OrderBy(n => n.last)); Print("Order by last, first",employees.OrderBy(n => n.last).ThenBy(n => n.first)); Print("order by salary", employees.OrderBy(n => n.salary)); Print("order by salary descending", employees.OrderByDescending(n => n.salary)); Console.Out.Write("press return to exit.");Console.In.ReadLine(); } static void Print(string title, IEnumerable<Employee> objects) { Console.WriteLine(title+":"); objects.ToList().ForEach(n => Console.WriteLine(n)); } } }Produces:
No ordering: Jones, Sara: $11000 Jones, Brad: $10000 Aaron, Mike: $10000 Xader, Xena: $20000 Order by last: Aaron, Mike: $10000 Jones, Sara: $11000 Jones, Brad: $10000 Xader, Xena: $20000 Order by last, first: Aaron, Mike: $10000 Jones, Brad: $10000 Jones, Sara: $11000 Xader, Xena: $20000 order by salary: Jones, Brad: $10000 Aaron, Mike: $10000 Jones, Sara: $11000 Xader, Xena: $20000 order by salary descending: Xader, Xena: $20000 Jones, Sara: $11000 Jones, Brad: $10000 Aaron, Mike: $10000 press return to exit.
- Set Operators
LINQ provides Union, Intersect, Distinct, and Except.
using System; using System.Collections.Generic; using System.Linq; namespace PlayingAround { class Sets { private static void Main() { int[] little = {0, 1, 2, 3, 4, 5, 6}; int[] big = {5, 6, 7, 8, 9, 10}; IEnumerable<int> all = little.Union(big); all.ToList().ForEach(n => Console.Write(n)); //writes 012345678910 Console.WriteLine(); IEnumerable<int> intersect = little.Intersect(big); intersect.ToList().ForEach(n => Console.Write(n)); //writes 56 Console.WriteLine(); IEnumerable<int> both = little.Concat(big); both.ToList().ForEach(n => Console.Write(n)); //writes 01234565678910 Console.WriteLine(); IEnumerable<int> dist = both.Distinct(); dist.ToList().ForEach(n => Console.Write(n)); //writes 012345678910 Console.WriteLine(); //"Except()" returns all elements of the first sequence that do not exist in the second IEnumerable<int> exceptional = little.Except(big); exceptional.ToList().ForEach(n => Console.Write(n)); //writes 01234 Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } } - Helper functions
Range, Reverse, Repeat, and Empty
using System; using System.Collections.Generic; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { class Range { private static void Main() { //note: Range. Empty and Repeat are not extension methods, but static ones IEnumerable<int> one2five = Enumerable.Range(1, 5); one2five.ToList().ForEach(n => Console.Write(n)); //writes: 12345 IEnumerable<int> five2one = one2five.Reverse(); five2one.ToList().ForEach(n => Console.Write(n)); //writes: 54321 IEnumerable<int> fivethrees = Enumerable.Repeat(3,5); fivethrees.ToList().ForEach(n => Console.Write(n)); //writes: 33333 //Empty creates an empty Enumerable of the specific type IEnumerable<int> empty = Enumerable.Empty<int>(); fivethrees.ToList().ForEach(n => Console.Write(n)); //writes: Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } } - NonDeferred Conversion Methods
ToArray, ToList, ToDictionary, and ToLookup
using System; using System.Collections.Generic; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { public class BookItem { public string author; public string title; public string rating; } class NonDeferred { private static void Main() { List<BookItem> books = new List<BookItem> { new BookItem {author = "Demarco", title = "PeopleWare", rating = "Good"}, new BookItem {author= "Tolkien", title= "The Hobbit", rating = "Super"}, new BookItem {author= "Pressfield", title = "Gates of Fire", rating = "Super"} }; //convert to an array BookItem[] bookItems = books.ToArray(); //convert to list List<BookItem> bookList = books.ToList(); //now, finally something interesting, the dictionary, (one key to one object) Dictionary<string, BookItem> dict = books.ToDictionary(b => b.author); Console.Out.WriteLine(dict["Tolkien"].title); //writes: The Hobbit //now for something even more interesting, a Lookup (one key, many objects) ILookup<string, BookItem> bookLookup = books.ToLookup(b => b.rating); IEnumerable<BookItem> superBooks = bookLookup["Super"]; foreach (var book in superBooks) { Console.WriteLine("A super book is "+book.title); //writes: The Hobbit, Gates of Fire } Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } } - Grabbing an item and searching for items
using System; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { class NonDeferred2 { private static void Main() { string[] names = {"Cindy", "Bobby", "Jan", "Peter", "Marcia", "Greg"}; bool eq = names.SequenceEqual(names.Reverse().Reverse()); //returns true // -- Finding an item //First grabs the first item Console.WriteLine(names.First()); //writes: "Cindy" Console.WriteLine(names.First(p => p.StartsWith("J"))); //writes: "Jan" Console.WriteLine(names.Last()); //writes: "Greg" //selects the last item that matches a function Console.WriteLine(names.Last(p => p.Length>4)); //writes: "Marcia" Console.WriteLine(names.LastOrDefault(p => p.Length > 8)); //writes: // -- Seaching for items //Single returns the only element of a sequence, or throws an exception try { Console.WriteLine(names.Single()); //throws InvalidOperationException: } catch(InvalidOperationException) { Console.WriteLine("I was expecting only one element"); } //with a predicate it returns the only one, or throws an exception Console.WriteLine(names.Single(p=>p.StartsWith("B"))); //writes: "Bobby" //ElementAt selects the element at that index (zero based) Console.WriteLine(names.ElementAt(2)); //writes: "Jan" //Any() returns true if the sequence has any elements Console.WriteLine(names.Any()); //writes: "true" //Any(p) return true if any element matches the predicate Console.WriteLine(names.Any(p => p.Length>3)); //writes: "true" //All(p) returns true only if all the elements match the condition Console.WriteLine(names.All(p => p.Length > 4)); //writes: "false" //Contains returns true if that object is in the sequence Console.WriteLine(names.Contains("Carol")); //writes: "false" Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } } - Common math functions
Count, Sum, Min, Max, and Average
using System; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { class Maths { private static void Main() { int[] fibs = {0, 1, 1, 2, 3, 5, 8}; Console.WriteLine(fibs.Count()); //writes: 7 Console.WriteLine(fibs.Count(p => p < 3)); //writes: 4 Console.WriteLine(fibs.Sum()); //writes: 20 Console.WriteLine(fibs.Min()); //writes: 0 Console.WriteLine(fibs.Max()); //writes: 8 Console.WriteLine(fibs.Average()); //writes: 2.85714285714286 Console.Out.Write("press return to exit.");Console.In.ReadLine(); } } } - Aggregate, the "Reduce" function in LINQ
using System; using System.Linq; //need this to get creamy goodness of IEnumerable<T> extension methods namespace PlayingAround { class Aggregate { private static void Main() { int[] numbers = {1, 2, 3, 4, 5, 6}; //Aggregate performs a function on each of the elements and carries the result //forward to the next element (Called a "Reduce" operation) int sumOfSquares = numbers.Aggregate(0, (sum,n) => n*n + sum); Console.Out.WriteLine("sumOfSquares = " + sumOfSquares); //writes: 91 //concatenate all the strings together string allwords = words.Aggregate("", (temp, word) => temp + word); Console.Out.WriteLine("allwords = {0}", allwords); //writes: onetwothree Console.ReadKey(); } } }
- Example using Standard Query Operators