After having a discussion on delegates, lambda expressions, and extension methods, we are now ready to continue our discussion about LINQ. In this chapter, we will delve into LINQ, which is essential in composing functional code. Here, we will discuss the following topics:
Language Integrated Query (LINQ), which was introduced in C# 3.0, is a language feature of .NET Framework that enables us to query data in collections easily implementing the IEnumerable<T>
interface, such as ArrayList<T>
, List<T>
, an XML document, and a database. It becomes easier to query any data in a collection since, using LINQ, we do not need to learn a different syntax for a different source of data. For instance, we don't need to learn SQL if we use LINQ when the data source is a database. Also, using LINQ, we don't have to learn XQuery when we deal with an XML document. Fortunately, LINQ has eased our use of a common syntax for all the sources of data.
There are two basic data units in LINQ; they are sequences, which include any object that implements IEnumerable<T>
, and elements, which include the items in the sequence. Suppose we have the following int
array named intArray
:
int[] intArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49 };
From the preceding collection, we can say that intArray
is a sequence, and the contents of the array, which include the numbers from 0 to 49, are the elements.
A sequence can be transformed using a method called a query operator. The query operator accepts an input sequence and then produce the transformed sequence. The query will transform the sequence when it is enumerated. The query consists of at least an input sequence and an operator. Let's take a look at the following code, which we can find in the SequencesAndElements.csproj
project, which will look for the prime number from our preceding collection, intArray
:
public partial class Program { public static void ExtractArray() { IEnumerable<int> extractedData = System.Linq.Enumerable.Where (intArray, i => i.IsPrime()); Console.WriteLine ("Prime Number from 0 - 49 are:"); foreach (int i in extractedData) Console.Write("{0} ", i); Console.WriteLine(); } }
The IsPrime()
extension method will have the following implementation:
public static class ExtensionMethods { public static bool IsPrime(this int i) { if ((i % 2) == 0) { return i == 2; } int sqrt = (int)Math.Sqrt(i); for (int t = 3; t <= sqrt; t = t + 2) { if (i % t == 0) { return false; } } return i != 1; } }
From our preceding code, we can see that we use the Where
operator, which can be found in the System.Linq.Enumerable
class, to transform the intArray
sequence into the extractedData
sequence, as shown in the following code snippet:
IEnumerable<int> extractedData = System.Linq.Enumerable.Where (intArray, i => i.IsPrime());
The extractedData
collection will now contain the prime numbers obtained from the intArray
collection. If we run the project, we will get the following output on the console:
We can actually modify our preceding code snippet in a simpler way since all query operators are extension methods and can be used directly in the collection. The modification of the preceding code snippet is as follows:
IEnumerable<int> extractedData = intArray.Where(i => i.IsPrime());
By modifying the invocation of the Where
operator, we will get the complete implementation, as follows:
public partial class Program { public static void ExtractArrayWithMethodSyntax() { IEnumerable<int> extractedData = intArray.Where(i => i.IsPrime()); Console.WriteLine("Prime Number from 0 - 49 are:"); foreach (int i in extractedData) Console.Write("{0} ", i); Console.WriteLine(); } }
If we run the preceding ExtractArrayWithMethodSyntax()
method, we will get the exact same output with the ExtractArray()
method.