Querying a List |
|
The Language Integrated Query |
Introduction to Querying |
When using for or foreach loops on a list, you get the value or a range of values inside of the loop. Once you exit the loop, the operation ends and you cannot access the value(s) that was(were) isolated. If you want to get the isolated value or an isolated list of values again, you would have to perform the operation (create the loop), again. In some cases, you may want to prepare and get one value, a few values, or a range of values for later use, or to use over and over again. To do this, you would create a value or a list of values and store that list in a variable, outside of any loop, then use the value or the list of values when needed. As applied to the for or the foreach loop, to perform this operation, you use a conditional statement that would examine the list, look for the value(s), get that value or those values that respond(s) to the condition. Any value(s) that respond(s) to the condition is(are) then stored in the new list. This technique of examining an array is referred to as querying. |
To support the ability to query a list, you can use the Language Integrated Query, abbreviated LINQ. To use LINQ in your application, you must include the System.Core.dll assembly in your program. If you started your application as an empty project:
In the .NET tab of the Add Reference dialog box, you can click System.Core Then click OK. You must then use the System.Linq namespace in your code or you should include the using System.Linq; line in your list of namespaces. If you create an application by selecting the Console Application option from the New Project dialog box, the studio would add the necessary assembly to your project and the necessary namespace to your code file.
To query a list, you write a statement using words and operators of the LINQ.
The most fundamental operation you can perform on LINQ consists of creating, also referred to as selecting, a list of values, from an existing list such as an array. The basic formula to use is: var SubListName = from ValueHolder in List select ValueHolder; The var keyword, the assignment operator "=", the from keyword, the in keyword, the select keyword, and the semicolon are required. The SubListName is a name of a new variable that will hold the list of values produced by this operation. The ValueHolder is the name of a variable that will be used to identify each resulting member of this operation. This variable will be equivalent to getting each member of the array that responds to a condition. The List factor represents the name of the variable that you would have created already. The List can be an array. Here is an example: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; var Number = from n in Numbers select n; foreach(var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } This would produce: Number: 12.44 Number: 525.38 Number: 6.28 Number: 2448.32 Number: 632.04 Press any key to continue . . . To make the code easier to read, you can spread the select statement to various lines. Here is an example: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; var Number = from n in Numbers select n; foreach(var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } We mentioned that the List factor of our formula could be an array. It can also be a collection-based variable; that is, a variable created from a collection-based class. The collection class you use must implement the IEnumerable generic interface. If you want, you can create your own class that implements this interface but the .NET Framework provides a complete set of classes that should suit every need. One of the built-in generic classes of the .NET Framework is called List and you can easily use it to create a list of values. Here is an example: using System; using System.Collections.Generic; public class Exercise { static int Main(string[] args) { var Numbers = new List<double>(); Numbers.Add(12.44); Numbers.Add(525.38); Numbers.Add(6.28); Numbers.Add(2448.32); Numbers.Add(632.04); return 0; } } After creating the collection, you can use the same LINQ formula we saw for an array. Here is an example: using System; using System.Linq; using System.Collections.Generic; public class Exercise { static int Main(string[] args) { var Numbers = new List<double>(); Numbers.Add(12.44); Numbers.Add(525.38); Numbers.Add(6.28); Numbers.Add(2448.32); Numbers.Add(632.04); var Number = from n in Numbers select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } This would produce the same result as seen earlier. Notice that, as always, the var keyword does not indicate the type of variable it is dealing with.
As you can see, simply using a select statement as done above produces the same list of values in the array. A criterion is a condition applied to a set of values to find out which one(s) respond(s) to the condition or validate the condition. When applied to an array, a criterion examines each member of the array, finds out what member responds to it, if so, adds that member to the from list. To apply a criterion, you create Boolean operation between the in statement and the select statement. This criterion is actually formulated using the where operator. The formula to use is: var SubListName = from ValueHolder in List where Condition select ValueHolder; In the new section, the where keyword is required. The Condition is formulated using the logical operators we studied in Lesson 9. It can be in the form of:
Remember that you must create the criterion as a Boolean operation. After applying the select statement, you can then use it as you see fit. For example, you can display its result(s) to the console. Here is an example: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers where n == 327 select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } This would produce: Number: 327 Press any key to continue . . . Of course, the purpose of querying a list is to isolate one or more values. As such, you can create an expression that checks a value and applies some condition to it. For example, in this list of numbers, you may want to find out whether it contains one or more numbers that are divisible by 5. This operation can be carried by the % operator as in "number % 5"; but number % 5 is pure algebra, not Boolean. Therefore, you must add a condition to make it a valid Boolean expression. For example, you can find out if the number % 5 operation is equal to 0. Here is an example: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers where n % 5 == 0 select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } This would produce: Number: 525 Press any key to continue . . . To make the statement easier to read and less confusing, you should make it a habit to isolate the groups of statements in parentheses: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers where (n % 5) == 0 select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } The above condition produced only one value because of the way the values exist in our array. A querying operation can also produce more than one value. Here is an example: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers where n % 2 == 0 select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } This would produce: Number: 102 Number: 44 Number: 38 Number: 6 Number: 28 Number: 632 Number: 104 Press any key to continue . . . Notice that the list includes only even numbers (those that are divisible by 2).
In Lesson 10, we saw that you could use logical conjunctions and disjunctions to combine two or more Boolean expressions. These also are available in LINQ. To do this, use the where statement to create the expression as you see fit. Here is an expression that uses a logical disjunction (&&) operation: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers where n % 2 == 0 && n <= 100 select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } This would produce: Number: 44 Number: 38 Number: 6 Number: 28 Press any key to continue . . . Once again, remember that the use of parentheses makes it easier to read the code and better understand it: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers where (n % 2 == 0) && (n <= 100) select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } Or better yet: using System; using System.Linq; public class Exercise { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers where ((n % 2) == 0) && (n <= 100) select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } }
When you create a list, you add the items in any order of your choice. For example, if you register the students of a school, you enter their information as it becomes available. In the same way, when you create a select statement, the items are added to its list in the order they appear in the main list. When treating the new list or when displaying it to the user, you may want to arrange it in alphabetical, numerical, or in chronological order. To support this operation, the LINQ provides the orderdy operator. To apply it, write the operator before the select operation followed by the from list. Here is an example: using System; using System.Linq; public class Program { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers orderby n select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } This would produce: Number: 6 Number: 28 Number: 38 Number: 44 Number: 102 Number: 104 Number: 327 Number: 525 Number: 632 Number: 24481 Press any key to continue . . . If you apply the orderby operator simply followed by a variable, the list is ordered alphabetically or numerically depending on the types of values in the list. This is referred to as ascending. To re-enforce this, you can follow the variable with the ascending keyword. Here is an example: using System; using System.Linq; public class Program { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers orderby n ascending select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } To arrange the list in reverse order, you can follow the variable name with the descending keyword. Here is an example: using System; using System.Linq; public class Program { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers orderby n descending select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } } This would produce: Number: 24481 Number: 632 Number: 525 Number: 327 Number: 104 Number: 102 Number: 44 Number: 38 Number: 28 Number: 6 Press any key to continue . . . You can apply a where condition to the statement to select just a few values. For example, to get a list of odd numbers arranged in numerical order, you would write the statement as follows: using System; using System.Linq; public class Program { static int Main(string[] args) { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; var Number = from n in Numbers where n % 2 != 0 orderby n ascending select n; foreach (var member in Number) Console.WriteLine("Number: {0}", member); return 0; } }
From what we have learned so far, the type of list produced by a LINQ statement is primarily based on one of the data types we reviewed in Lesson 2 and in Lesson 3 (integers, double-precision numbers, strings, and date/time values). In Lesson 17, we saw that the integer and numeric types are in fact structures of the .NET Framework. As such, they are equipped with properties and methods. In your LINQ statement, you can explore the characteristics of those data types as you see fit.
If you create a string-based collection, you can use the properties and methods of the String class to refine the list produced by your LINQ statement. To do this, in the list produced by the where statement, you can access any of the properties or you can call any desired method of the String class using the period operator. For example, to get a list of names that start with a certain letter, you can call the StartsWith() method as follows: using System; using System.Linq; public class Program { static int Main(string[] args) { var Name = new[] { "Hermine", "Patrick", "Hank", "Bertine", "Julius", "Thomas", "Jeannette", "Patricia", "Henriette", "Raul", "David", "Paulette" }; var Names = from n in Name where n.StartsWith("P") // orderby n ascending select n; foreach (var member in Names) Console.WriteLine("Name: {0}", member); return 0; } } Or to get a list of names that end with a certain sub-string, you would call the String.EndsWith() method. Here is an example: using System; using System.Linq; public class Program { static int Main(string[] args) { var Name = new[] { "Hermine", "Patrick", "Hank", "Bertine", "Julius", "Thomas", "Jeannette", "Patricia", "Henriette", "Raul", "David", "Paulette" }; var Names = from n in Name where n.EndsWith("ette") // orderby n ascending select n; foreach (var member in Names) Console.WriteLine("Name: {0}", member); return 0; } } In the same ways, to create a list of names that contain a certain sub-string, you can call the String.Contains() method as follows: using System; using System.Linq; public class Program { static int Main(string[] args) { var Name = new[] { "Hermine", "Patrick", "Hank", "Bertine", "Julius", "Thomas", "Jeannette", "Patricia", "Henriette", "Raul", "David", "Paulette" }; var Names = from n in Name where n.Contains("au") // orderby n ascending select n; foreach (var member in Names) Console.WriteLine("Name: {0}", member); return 0; } }
To create more effective LINQ statements, you can use many of the features of the C# language we have studied in previous lessons. For example, instead of using one of the primitive types to create your list as we have done so far, you may want to use your own class. You can start by creating the class normally as you see fit. Here is an example: public class Person { public string FirstName; public string LastName; public char Gender; public Person(string First, string Last, char Sex) { FirstName = First; LastName = Last; Gender = Sex; } } Obviously before considering the class in your LINQ statement, you should first create a collection variable that would hold its values. You can create the list as an array. Once the list is ready, when formulating your LINQ statement, use the from variable to access a member of the class using the period operator. Here is an example: using System; using System.Linq; public class Person { public string FirstName; public string LastName; public char Gender; public Person(string First, string Last, char Sex) { FirstName = First; LastName = Last; Gender = Sex; } } public class Program { static int Main(string[] args) { var People = new Person[] { new Person("Paulette", "Cranston", 'F'), new Person("Harry", "Kumar", 'M'), new Person("Jules", "Davidson", 'M'), new Person("Leslie", "Harrington", 'U'), new Person("Ernest", "Colson", 'M'), new Person("Patricia", "Katts", 'F'), new Person("Patrice", "Abanda", 'U'), new Person("Frank", "Thomasson", 'M') }; var Persons = from Pers in People select Pers.LastName; foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual); return 0; } } This would produce: Person Name: Cranston Person Name: Kumar Person Name: Davidson Person Name: Harrington Person Name: Colson Person Name: Katts Person Name: Abanda Person Name: Thomasson Press any key to continue . . . In the same way, you can use any of the regular C# operators to produce any result of your choice. For example, when studying strings, we saw that you could use the + operator to combine strings. Here is an example: using System; using System.Linq; public class Person { public string FirstName; public string LastName; public char Gender; public Person(string First, string Last, char Sex) { FirstName = First; LastName = Last; Gender = Sex; } } public class Program { static int Main(string[] args) { var People = new Person[] { new Person("Paulette", "Cranston", 'F'), new Person("Harry", "Kumar", 'M'), new Person("Jules", "Davidson", 'M'), new Person("Leslie", "Harrington", 'U'), new Person("Ernest", "Colson", 'M'), new Person("Patricia", "Katts", 'F'), new Person("Patrice", "Abanda", 'U'), new Person("Frank", "Thomasson", 'M') }; var Persons = from Pers in People select Pers.LastName + ", " + Pers.FirstName; foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual); return 0; } } This would produce: Person Name: Cranston, Paulette Person Name: Kumar, Harry Person Name: Davidson, Jules Person Name: Harrington, Leslie Person Name: Colson, Ernest Person Name: Katts, Patricia Person Name: Abanda, Patrice Person Name: Thomasson, Frank Press any key to continue . . . Remember that the essence of querying a list is to create a list of particular data based on a criterion, which is done by applying a where condition. Here is an example: public class Program { static int Main(string[] args) { var People = new Person[] { new Person("Paulette", "Cranston", 'F'), new Person("Harry", "Kumar", 'M'), new Person("Jules", "Davidson", 'M'), new Person("Leslie", "Harrington", 'U'), new Person("Ernest", "Colson", 'M'), new Person("Patricia", "Katts", 'F'), new Person("Patrice", "Abanda", 'U'), new Person("Frank", "Thomasson", 'M') }; var Persons = from Pers in People where Pers.Gender == 'F' select Pers.LastName + ", " + Pers.FirstName; foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual); return 0; } } This would produce: Person Name: Cranston, Paulette Person Name: Katts, Patricia Press any key to continue . . . To perform a more particular operation on a class, you can create a method in it and then call that method in your LINQ statement. This means that, just as you can access a field or a property of the class, you can access any of its internal or public methods. Here is an example: using System; using System.Linq; public class Person { public string FirstName; public string LastName; public char Gender; public Person(string First, string Last, char Sex) { FirstName = First; LastName = Last; Gender = Sex; } internal string GetFullName() { return LastName + ", " + FirstName; } } public class Program { static int Main(string[] args) { var People = new Person[] { new Person("Paulette", "Cranston", 'F'), new Person("Harry", "Kumar", 'M'), new Person("Jules", "Davidson", 'M'), new Person("Leslie", "Harrington", 'U'), new Person("Ernest", "Colson", 'M'), new Person("Patricia", "Katts", 'F'), new Person("Patrice", "Abanda", 'U'), new Person("Frank", "Thomasson", 'M') }; var Persons = from Pers in People where Pers.Gender == 'M' select Pers.GetFullName(); foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual); return 0; } } This would produce: Person Name: Kumar, Harry Person Name: Davidson, Jules Person Name: Colson, Ernest Person Name: Thomasson, Frank Press any key to continue . . .
There are two types of built-in classes you can use in your application when it comes to LINQ. You can use any of the non-generic collection classes to create a list of values. The other category is the generic collection classes.
We saw that you can get the result of a LINQ statement from the select section. In reality, the select statement simply indicates that the result is ready and it hands it to the other parts of the program. Instead of getting the result directly from the select statement, you can first store it in a local LINQ variable. This allows you to treat the result as a variable that you can then manipulate before getting the final result. To create a local variable in the LINQ statement, you can use the let operator. You must use it before the select statement to hold the result. Here is an example: public class Program { static int Main(string[] args) { var Persons = from Pers in People let FullName = Pers.LastName + ", " + Pers.FirstName select FullName; foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual); return 0; } } If you need a where condition but your let variable would be used only to hold the final result, you can create that variable after the where statement. Here is an example: public class Program { static int Main(string[] args) { var Persons = from Pers in People where Pers.Gender == 'U' let FullName = Pers.LastName + ", " + Pers.FirstName select FullName; foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual); return 0; } } In this case, you can create the let variable before the where statement and you would get the same result: using System; using System.Linq; public class Person { public string FirstName; public string LastName; public char Gender; public Person(string First, string Last, char Sex) { FirstName = First; LastName = Last; Gender = Sex; } } public class Program { static int Main(string[] args) { var People = new Person[] { new Person("Paulette", "Cranston", 'F'), new Person("Harry", "Kumar", 'M'), new Person("Jules", "Davidson", 'M'), new Person("Leslie", "Harrington", 'U'), new Person("Ernest", "Colson", 'M'), new Person("Patricia", "Katts", 'F'), new Person("Patrice", "Abanda", 'U'), new Person("Frank", "Thomasson", 'M') }; var Persons = from Pers in People let FullName = Pers.LastName + ", " + Pers.FirstName where Pers.Gender == 'U' select FullName; foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual); return 0; } } This would produce: Person Name: Harrington, Leslie Person Name: Abanda, Patrice Press any key to continue . . .
To get the final result of a query, you may want to combine a few fields or properties of each member of the result. For example, as we have seen so far, you may want to combine the last and the first name of each result to create a full name. Besides, or instead of, the let operator, you can use the new operator to create such a combination. To use the new operator, after the select keyword, type new followed by an opening and a closing curly brackets. Inside the brackets, create an expression as you see fit and assign it to a local variable in the curly brackets. When accessing the result in your foreach loop, apply the period operator on the foreach variable to access the new local variable. Here is an example: public class Person { public string FirstName; public string LastName; public char Gender; public Person(string First, string Last, char Sex) { FirstName = First; LastName = Last; Gender = Sex; } } public class Program { static int Main(string[] args) { var People = new Person[] { new Person("Paulette", "Cranston", 'F'), new Person("Harry", "Kumar", 'M'), new Person("Jules", "Davidson", 'M'), new Person("Leslie", "Harrington", 'U'), new Person("Ernest", "Colson", 'M'), new Person("Patricia", "Katts", 'F'), new Person("Patrice", "Abanda", 'U'), new Person("Frank", "Thomasson", 'M') }; var Persons = from Pers in People select new {FullName=Pers.LastName+", "+Pers.FirstName }; foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual.FullName); return 0; } } To make the statement easier to read, you can span it on various lines: public class Program { static int Main(string[] args) { var Persons = from Pers in People select new { FullName = Pers.LastName + ", " + Pers.FirstName }; foreach (var Individual in Persons) Console.WriteLine("Person Name: {0}", Individual.FullName); return 0; } } |
|
||
Previous | Copyright © 2008-2016, FunctionX, Inc. | Next |
|