1. Benefits of using LINQ - primitive types
- Filtering
- Sorting
2. Using LINQ with classes
- Filtering
- Grouping
- Grouping with math functions
- Grouping by multiple items
- Using Grouping to select a disctint set
- Distinct
3. Single, First and FirstOrDefault
4. How to write for each
5. Multiple sets manipulation
- Joining 2 sets
- Left outer join
- Combining sets
- SelectMany
6. Zip
7. Aggregate
8. OfType
9. Using let
10. Debuging LINQ query
101 examples on MSDN
Before you start using LINQ, you need to include proper namespace by: using System.Linq;
1. Benefits of using LINQ - primitive types
C# string[] codes = new string[] { "abc", "def", "ddf" };and you want to select a subset of the elements in the array. You can write a code like this:
C# List<string> selection = new List<string>(); foreach (string s in codes) { if (s.StartsWith("d")) selection.Add(s); }
Filtering
C# var selection = (from s in codes where s.StartsWith("d") select s).ToList(); var selection = codes.Where(s => s.StartsWith("d")).ToList();
Sorting
C# var selection = (from s in codes where s.StartsWith("d") orderby s[1],s[0] descending select s).ToList(); var selection = codes.Where(s => s.StartsWith("d")).OrderBy(s => s[1]).ThenByDescending(s => s[0]).ToList();
2. Using LINQ with classes
C# //define a class that represents person class Person { public string DepartmentId; public string Name; public int Age; } // populate people List<Person< people = new List<Person>() { new Person() { DepartmentId = "IT", Name = "John", Age=32 }, new Person() { DepartmentId = "FI", Name = "Paul", Age=43 }, new Person() { DepartmentId = "FI", Name = "George", Age=28 } };
Filtering
C# // select whole classes from the list List<Person> itPeople = people.Where(p => p.DepartmentId == "IT").ToList(); // if you want only people names List<string> itPeopleNames = people.Where(p => p.DepartmentId == "IT").Select(p => p.Name).ToList();
Grouping
C# var groups = from p in people group p by p.DepartmentId into g select new { MyKey = g.Key, MyGroup = g }; var groups1 = people.GroupBy(p => p.DepartmentId).Select( g => new { MyKey = g.Key, MyGroup = g }); // iterate over result foreach (var gr in groups1) { string key = gr.MyKey; foreach (var p in gr.MyGroup) { Person person = p; } }
Grouping with math functions
C# var averages = from p in people group p by p.DepartmentId into g select new { MyKey = g.Key, AvgAge = g.Average(p => p.Age) }; var averages1 = people.GroupBy(p => p.DepartmentId).Select(g => new { MyKey = g.Key, MyAvg = g.Average(p => p.Age) });
Grouping by multiple items
C# var averages2 = people .GroupBy(p => new { p.DepartmentId, p.Age }) .Select(g => new { DeptId = g.Key.DepartmentId, Age = g.Key.Age, Salary = g.Average(p => p.Salary) });
Using Grouping to select a disctint set
C# var disctincList = people .GroupBy(p => new { p.Name, p.DepartmentId }) .Select(g => g.First());
Distinct
C# IEnumerable<Person> disctinctSet = people.Distinct(); IEnumerable<Person> disctinctSet1 = (from p in people select p).Distinct();
3. Single, First and FirstOrDefault
C# First - returns first element of sequence. Throws exception when the sequence is empty FirstOrDefault - returns first element of sequence. If the sequence is empty, returns an empty object Single - returns first element of sequence. Throws exception when the sequence is empty or has more than 1 element
4. How to write for each
C# foreach (var p in persons) { p.LastName = "John"; }it is possible to see foreach written in LINQ as below
C# persons.Select(p => { p.LastName = "John"; return p; } ).ToList(); persons.All(p => { p.LastName = "John"; return true; } ).ToList();
5. Multiple sets manipulation
Joining 2 sets
C# // class that presents a departement class DepartmentO { public string DepartmentId; public string Name; } // populate departments List<DepartmentO> departments = new List>DepartmentO>() { new DepartmentO() { DepartmentId = "IT", Name = "Information Technology"}, new DepartmentO() { DepartmentId = "FI", Name = "Finance"}, }; // class that presents combined result for person and departement class PersonWithDepartment { public string DepartmentId; public string PersonName; public string DepartmentName; }Now you can populate both sets and combine result with LINQ.
C# // join two object sets - option 1 IEnumerable<PersonWithDepartment> joinedSet = from d in departments join p in people on d.DepartmentId equals p.DepartmentId select new PersonWithDepartment() { DepartmentId = p.DepartmentId, PersonName = p.Name, DepartmentName = d.Name }; // join two object sets - option 2 IEnumerable<PersonWithDepartment> joinedSet2 = people.Join( departments, (p) => (p.DepartmentId), (d) => (d.DepartmentId), (p, d) => new PersonWithDepartment() { DepartmentId = p.DepartmentId, PersonName = p.Name, DepartmentName = d.Name } );
Left outer join
C# var outerJoinSet = from p in people join d in departments on p.DepartmentId equals d.DepartmentId into d1 from d2 in d1.DefaultIfEmpty() select new { DepartmentId = p.DepartmentId, PersonName = p.Name, DepartmentName = d2.Name };
Combining sets
C# // create NEW set as union of two sets List<Person> union = people.Union( new List<Person>() {new Person() { DepartmentId = "IT", Name = "George" }}).ToList(); // add people to existing set people.AddRange( new List<Person>() { new Person() { DepartmentId = "IT", Name = "George" } }); // concatenate existing 2 lists - the original lists remain untouched, no new Person element gets allocated var list1 = new List<PersonO>() { new PersonO() { DepartmentId = "IT", Name = "John" } }; var list2 = new List<PersonO>() { new PersonO() { DepartmentId = "FI", Name = "George" } }; List<PersonO> concatenated = list1.Concat(list2).ToList();
SelectMany
C# // cross join var list1 = new string[] { "1", "2", "3" }; var list2 = new string[] { "A", "B" }; var result1 = list1.SelectMany(l1 => list2, (l1, l2) => new { l1, l2 }); // result: {1,A}, {1,B}, {2,A}, {2,B}, {3,A}, {3,B} // list of lists flattening var masterList = new List>string[]>() { list1, list2 }; var result2 = masterList.SelectMany(i => i); // result 2: 1,2,3,A,B
6. Zip
C# string[] list1 = { "a", "b", "c" }; string[] list2 = { "X", "Y" }; var zipped = list1.Zip(list2, (i1, i2) => i1 + i2); foreach (var item in zipped) { Console.WriteLine(item); } // Output // aX // bY
7. Aggregate
C# var input = new []{1,2,3,4,5}; var result = input.Aggregate((a,b) => a * b); // you can seed initial value var result = input.Aggregate(10, (a,b) => a * b);
8. OfType
C# System.Collections.ArrayList objects = new System.Collections.ArrayList(2); objects.Add("First"); objects.Add(1); IEnumerable<string> strings = objects.OfType<string>();
9. Using let
C# var list = new string[] { "abc_1", "def_11", "xyz_3" }; var result = from item in list let number = Convert.ToInt16(item.Split('_')[1]) where number > 2 orderby number select item; result = list .Select(item => new { Item = item, Code = Convert.ToInt16(item.Split('_')[1]) }) .Where(i => i.Code > 2) .OrderBy(i => i.Code) .Select(i => i.Item); // result: xyz_3, def_11
10. Debuging LINQ query
C# var numbers = new int[] { 1, 2, 3 }; var result = numbers .Where(n => n > 2);It can be done without rewriting to foreach loop, but some code injection is necessary.
C# var result1 = numbers .Select( item => { return item; // set breakpoint here - you will see 1,2,3 }) .Where(n => n > 2) .Select( item => { return item; // set breakpoint here - you will see 3 }); // the breakpoint will be hit when code reaches ToList() var result1debug = result1.ToList();If you want to examine the the evaluation of the where condition
C# var result2 = numbers .Where( n => { bool b = n > 2; return b; // set breakpoint here }); var result2debug = result2.ToList();