This article explains LINQ operations. Language Integrated Query (LINQ) is a set of language and framework features for constructing type-safe queries over local collections or remote data sources. It was introduced in C# 3.0 and .Net Framework 3.5.
The basic unit of data in LINQ is a sequence of elements that actually implements IEnumerable. In the following example, Employees is a sequence and “John”, ”Dave”, ”Black” and ”Jack” are elements.
- string[] employees = {"John","Dave","Black","Jack"};
A query operator is the one that transforms the sequence. A typical query operator accepts a sequence and emits a transformed output sequence. For the IEnumerable case, we have around 40 query operators. They are also known as standard operators.
Let us get started with a few simple queries.
Note: I will use LINQPAD to run these queries. Hence, the final statement dump is specific to it. It's basically used to show the output.
- string[] employees = {"John","Dave","Black","Jack","Rahul"};
-
- IEnumerable<string> filtered_emp = employees.Where(n=>n.Length>4);
-
- filtered_emp.Dump("Simple usage of Query");
Since standard query operators are implemented as static methods, we can directly call Where on employees. Most query operators accept lambda expressions as an argument like here we have n=>n.Length>4.
Now, let's look at a complex query.
- string[] employees = {"John","Dave","Black","Jack","Rahul"};
-
- IEnumerable<string> query = employees.Where(n=>n.Contains("a"))
- .OrderBy(n=>n.Length)
- .Select(n=>n.ToLower());
-
- query.Dump("Simple usage of Query");
Here, what it is doing is taking the input, extracting all the strings containing the letter "
a", then sorting them by length and then converting that to lower case. Here, the variable "
n" is privately scoped to each lambda expression. OrderBy and Select are standard query Operators.
Now, let's look at the Range Variable. The Identifier immediately following the from keyword syntax is called the Range variable. For instance, in the following example:
- from n in new[] { "John","Dave","Black","Jack","Rahul" }
- where n.Contains ("a")
- select n
The chaining of the query operator is very efficient in many cases as in the following.
- string[] names = { "John","Dave","Black","Jack","Rahul" };
-
- IEnumerable<string> query = names
- .Where (n => n.Contains ("a"))
- .OrderBy (n => n.Length)
- .Select (n => n.ToUpper());
-
- query.Dump();
-
-
-
- IEnumerable<string> filtered = names.Where (n => n.Contains ("a"));
- IEnumerable<string> sorted = filtered.OrderBy (n => n.Length);
- IEnumerable<string> finalone = sorted.Select (n => n.ToUpper());
-
- filtered.Dump ("Filtered");
- sorted.Dump ("Sorted");
- finalone.Dump ("FinalQuery");
So, as you can see in the preceding example, the same final query is done in the first expression and again the same thing is done differently by writing it progressively. Similarly, sometimes we need to keep the natural ordering of numbers as it is.
- int[] numbers = { 10, 9, 8, 7, 6 };
-
- numbers.Take (3) .Dump ("Take(3) returns the first three numbers in the sequence");
- numbers.Skip (3) .Dump ("Skip(3) returns all but the first three numbers in the sequence");
- numbers.Reverse() .Dump ("Reverse does exactly as it says");
Now in the end there are other important operators that are equally important.
- int[] numbers = { 10, 9, 8, 7, 6 };
-
-
-
- numbers.First().Dump ("First");
- numbers.Last().Dump ("Last");
-
- numbers.ElementAt (1).Dump ("Second number");
- numbers.OrderBy (n => n).First().Dump ("Lowest number");
- numbers.OrderBy (n => n).Skip(1).First().Dump ("Second lowest number");
-
-
-
- numbers.Count().Dump ("Count");
- numbers.Min().Dump ("Min");
-
-
-
- numbers.Contains (9).Dump ("Contains (9)");
- numbers.Any().Dump ("Any");
- numbers.Any (n => n % 2 != 0).Dump ("Has an odd numbered element");
-
-
-
- int[] seq1 = { 1, 2, 3 };
- int[] seq2 = { 3, 4, 5 };
- seq1.Concat (seq2).Dump ("Concat");
- seq1.Union (seq2).Dump ("Union");
Thanks for joining me.