Without LINQ, we would have to go through the values one-by-one and then find
the required details. However, using LINQ we can directly query collections and
filter the required values without using any looping. LINQ provides powerful
filtering, ordering, and grouping capabilities that requires minimum coding. For
example, if we want to find out the types stored in an assembly and then filter
the required details, we can use LINQ to query the assembly details using System.Reflection classes. The System.Reflection namespace contains
types that retrieve information about assemblies, modules, members, parameters,
and other entities as collections are managed code, by examining their metadata.
Also, files under a directory are a collection of objects that can be queried
using LINQ. We shall see some of the examples for querying some collections.
Array of Integers
The following example shows an integer array that
contains a set of integers. We can apply the LINQ queries on the array to fetch
the required values.
int[] integers = { 1, 6, 2, 27, 10, 33, 12, 8, 14, 5
}; IEnumerable<int> twoDigits = from numbers in
integers where numbers >= 10 select numbers;
Console.WriteLine("Integers > 10:"); foreach (var number in
twoDigits) { Console.WriteLine(number); }
The integers variable contains an array of
integers with different values. The variable twoDigits, which is of type
IEnumerable, holds the query. To get the actual result, the query has to be
executed.
The actual query execution happens when the query
variable is iterated through the foreach loop by calling GetEnumerator() to enumerate the
result. Any variable of type IEnumerable<T>, can be
enumerated using the foreach
construct. Types that support IEnumerable<T> or a derived
interface such as the generic IQueryable<T>, are called
queryable types. All collections such as list, dictionary and other classes are
queryable. There are some non-generic IEnumerable collections like ArrayList that can also be queried
using LINQ. For that, we have to explicitly declare the type of the range
variable to the specific type of the objects in the collection, as it is
explained in the examples later in this article.
The twoDigits variable will hold the query
to fetch the values that are greater than or equal to 10. This is used for
fetching the numbers one-by-one from the array. The foreach loop will execute the query
and then loop through the values retrieved from the integer array, and write it
to the console. This is an easy way of getting the required values from the
collection.
If we want only the first four values from a collection,
we can apply the Take() query
operator on the collection object. Following is an example which takes the
first four integers from the collection. The four integers in the resultant
collection are displayed using the foreach method.
IEnumerable<int> firstFourNumbers =
integers.Take(4); Console.WriteLine("First 4 numbers:"); foreach
(var num in firstFourNumbers) { Console.WriteLine(num);
}
The opposite of Take() operator is Skip() operator, which is used to skip
the number of items in the collection and retrieve the rest. The following
example skips the first four items in the list and retrieves the remaining.
IEnumerable<int> skipFirstFourNumbers =
integers.Skip(4); Console.WriteLine("Skip first 4 numbers:");
foreach (var num in skipFirstFourNumbers) {
Console.WriteLine(num); }
This example shows the way to take or skip the specified
number of items from the collection. So what if we want to skip or take the
items until we find a match in the list? We have operators to get this. They are
TakeWhile() and SkipWhile().
For example, the following code shows how to get the
list of numbers from the integers collection until 50 is found.
TakeWhile() uses an expression
to include the elements in the collection as long as the condition is true and
it ignores the other elements in the list. This expression represents the
condition to test the elements in the collection for the match.
int[] integers = { 1, 9, 5, 3, 7, 2, 11, 23, 50, 41, 6,
8 }; IEnmerable<int> takeWhileNumber = integers.TakeWhile(num
=> num.CompareTo(50) != 0); Console.WriteLine("Take while
number equals 50"); foreach (int num in takeWhileNumber)
{ Console.WriteLine(num.ToString()); }
Similarly, we can skip the items in the collection using
SkipWhile(). It uses an
expression to bypass the elements in the collection as long as the condition is
true. This expression is used to evaluate the condition for each element in the
list. The output of the expression is boolean. If the expression returns false,
the remaining elements in the collections are returned and the expression will
not be executed for the other elements. The first occurrence of the return value
as false will stop the expression for the other elements and returns the
remaining elements. These operators will provide better results if used against
ordered lists as the expression is ignored for the other elements once the first
match is found.
IEnumerable<int> skipWhileNumber =
integers.SkipWhile(num => num.CompareTo(50) != 0);
Console.WriteLine("Skip while number equals 50"); foreach (int num in
skipWhileNumber) { Console.WriteLine(num.ToString()); }
Collection of Objects
In this section we will see how we can query a custom
built objects collection. Let us take the Icecream object, and build the
collection, then we can query the collection. This Icecream class in the
following code contains different properties such as Name, Ingredients, TotalFat, and Cholesterol.
public class Icecream { public string
Name { get; set; } public string Ingredients { get; set; }
public string TotalFat { get; set; } public string Cholesterol { get;
set; } public string TotalCarbohydrates { get; set; }
public string Protein { get; set; } public double Price { get; set;
} }
Now build the Icecreams list collection using the
class defined perviously.
List<Icecream> icecreamsList = new List<Icecream>
{ new Icecream {Name="Chocolate Fudge Icecream",
Ingredients="cream, milk, mono and diglycerides...",
Cholesterol="50mg", Protein="4g", TotalCarbohydrates="35g",
TotalFat="20g", Price=10.5 }, new
Icecream {Name="Vanilla Icecream",
Ingredients="vanilla extract, guar gum, cream...",
Cholesterol="65mg", Protein="4g", TotalCarbohydrates="26g",
TotalFat="16g", Price=9.80 }, new Icecream {Name="Banana Split
Icecream", Ingredients="Banana, guar gum, cream...",
Cholesterol="58mg", Protein="6g", TotalCarbohydrates="24g", TotalFat="13g", Price=7.5 }
};
We have icecreamsList collection which
contains three objects with values of the Icecream type. Now let us say we have
to retrieve all the ice-creams that cost less. We can use a looping method,
where we have to look at the price value of each object in the list one-by-one
and then retrieve the objects that have less value for the Price property. Using LINQ, we can
avoid looping through all the objects and its properties to find the required
ones. We can use LINQ queries to find this out easily. Following is a query that
fetches the ice-creams with low prices from the collection. The query uses the
where condition, to do this.
This is similar to relational database queries. The query gets executed when the
variable of type IEnumerable is
enumerated when referred to in the foreach loop.
List<Icecream> Icecreams =
CreateIcecreamsList(); IEnumerable<Icecream> IcecreamsWithLessPrice
= from ice in Icecreams where ice.Price < 10 select
ice; Console.WriteLine("Ice Creams with price less than 10:");
foreach (Icecream ice in IcecreamsWithLessPrice) {
Console.WriteLine("{0} is {1}", ice.Name, ice.Price); }
As we used List<Icecream> objects, we can
also use ArrayList to hold the
objects, and a LINQ query can be used to retrieve the specific objects from the
collection according to our need. For example, following is the code to add the
same Icecreams objects to the
ArrayList, as we did in the
previous example.
ArrayList arrListIcecreams = new ArrayList();
arrListIcecreams.Add( new Icecream {Name="Chocolate Fudge Icecream",
Ingredients="cream, milk, mono and diglycerides...",
Cholesterol="50mg", Protein="4g", TotalCarbohydrates="35g",
TotalFat="20g", Price=10.5 }); arrListIcecreams.Add( new Icecream
{Name="Vanilla Icecream", Ingredients="vanilla extract, guar gum,
cream...", Cholesterol="65mg", Protein="4g",
TotalCarbohydrates="26g", TotalFat="16g", Price=9.80 });
arrListIcecreams.Add( new Icecream {Name="Banana Split Icecream",
Ingredients="Banana, guar gum, cream...", Cholesterol="58mg",
Protein="6g", TotalCarbohydrates="24g", TotalFat="13g", Price=7.5 });
Following is the query to fetch low priced ice-creams
from the list.
var queryIcecreanList = from Icecream icecream in
arrListIcecreams where icecream.Price < 10 select icecream;
Use the foreach loop, shown as follows, to display the
price of the objects retrieved using the above query.
foreach (Icecream ice in
queryIcecreanList) Console.WriteLine("Icecream Price : " +
ice.Price);
|