September 20, 2012

LINQ Features

There are two types of codes present but here we talk about declarative. First I describe both of them.

Imperative:

You describe how to accomplish the task by indicating each step in code.

Declarative:

You describe the final result needed, leaving the steps up to the query language.

LINQ is a declarative syntax which makes some computational tasks easier. We call this language the query language, because it is very useful for retrieving information from data bases by formulating queries, or questions, expressed in the language.

Let's explore query expressions. Query expressions are built with declarative clauses that specify the results you want, not how you want to achieve them. Let's check out this program that uses a query expression on an in-memory array of integers.

int[] array = { 1, 2, 3, 6, 7, 8 };

// Query expression.
var elements = from element in array
       orderby element descending
       where element > 2
       select element;

// Enumerate.
foreach (var element in elements)
{
    Console.Write(element);
    Console.Write(' ');
}

Now I discuss each phase of LINQ briefly here.

1) Conversion :

These extension methods perform a conversion from an IEnumerable collection into a certain collection: an array, Dictionary, List or Lookup data structure. We describe the methods, which are some of the most useful in the System.Linq namespace.

a) ToArray:

           int[] array1 = { 5, 4, 1, 2, 3 };
           var query = from element in array1
                 orderby element
                 select element;

           int[] array2 = query.ToArray();
           foreach (int value in array2)
          {
                 Console.WriteLine(value);
          }

         Output        
         1
         2
         3
         4
         5
b) ToDictionary:

          int[] values = new int[ ]  { 1, 3, 5, 7 };
          Dictionary<int, bool> dictionary = values.ToDictionary(v => v, v => true);

          foreach (KeyValuePair<int, bool> pair in dictionary)
         {
                 Console.WriteLine(pair);
         }

         Output

         [1, True]
         [3, True]
         [5, True]
         [7, True]
c) ToList:

         string[] array = new string[ ] { "A", "B", "C", "D" };
         List<string> list = array.ToList();
         Console.WriteLine(list.Count);
         foreach (string value in list)
         {
               Console.WriteLine(value);
         }

         Output

        4
       A
       B
       C
       D
d) ToLookup:

          string[] array = { "cat", "dog", "horse" };
          var lookup = array.ToLookup(item => item.Length);
  
          foreach (string item in lookup[3])
         {
                Console.WriteLine("3 = " + item);
         }

         foreach (string item in lookup[5])
        {
              Console.WriteLine("5 = " + item);
        }

        foreach (var grouping in lookup)
       {
            Console.WriteLine("Grouping:");
    
           foreach (string item in grouping)
          {
                     Console.WriteLine(item);
          }
      }

       Output

         3 = cat
         3 = dog
         5 = horse
        Grouping:
        cat
        dog
        Grouping:
         horse

2) Mutation :

 These methods filter or mutate one or more collections by change the elements in your query in some way: by removing unneeded elements, by adding new elements, or by changing other aspects of the elements themselves.  
  • AsEnumerable
  • AsParallel
  • Cast
  • Concat
  • DefaultIfEmpty
  • Distinct
  • ElementAt
  • ElementAtOrDefault
  • Except
  • First
  • FirstOrDefault
  • GroupBy
  • GroupJoin
  • Intersect
  • Join
  • Last
  • LastOrDefault
  • OfType
  • OrderBy
  • OrderByDescending
  • Reverse
  • Select
  • SelectMany
  • Single
  • SingleOrDefault
  • Union
  • Where
  • Zip

3) Skip and Take :


These extension methods are particularly useful. They eliminate the need for you to compose custom code to check ranges. They are recommended in a variety of contexts in your programs.

a) Skip:

          int[] array = { 1, 3, 5, 7, 9, 11 };
          var items1 = array.Skip(2);
         foreach (var value in items1)
        {
              Console.WriteLine(value);
        }

       var items2 = array.Skip(4);
       foreach (var value in items2)
      {
            Console.WriteLine(value);
      }

       Output

        5      The first two numbers in the array are missing.
        7
        9
       11

        9      The first four numbers are skipped.
       11
b) SkipWhile:

         int[] array = { 1, 3, 5, 10, 20 };
        var result = array.SkipWhile(element => element < 10);
        foreach (int value in result)
       {
                Console.WriteLine(value);
       } 

       Output

      10
      20
c) Take:

           List<string> list = new List<string>();
  list.Add("cat");
                list.Add("dog");
  list.Add("programmer");

           var first = list.Take(2);
           foreach (string s in first)
          {
                    Console.WriteLine(s);
          }
          Console.WriteLine();

         var last = list.Reverse<string>().Take(2);
         foreach (string s in last)
        {
                Console.WriteLine(s);
        }
        Console.WriteLine();

        Output

         cat
        dog

        programmer
        dog
d) TakeWhile:

          int[] values = { 1, 3, 5, 8, 10 };
         
          var result = values.TakeWhile(item => item % 2 != 0);
          foreach (int value in result)
          {
                 Console.WriteLine(value);
         }

           Output
           1
           3
           5

4) Computation :

They are also called computational methods. These act upon a certain query and then return a number or other value. These can also simplify your code, by eliminating the requirement of computing values such as averages yourself.

a) Aggregate:

int[] array = { 1, 2, 3, 4, 5 };
int result = array.Aggregate((a, b) => b + a);
// 1 + 2 = 3
// 3 + 3 = 6
// 6 + 4 = 10
// 10 + 5 = 15
Console.WriteLine(result);

result = array.Aggregate((a, b) => b * a);
// 1 * 2 = 2 // 2 * 3 = 6 // 6 * 4 = 24 // 24 * 5 = 120
Console.WriteLine(result);

Output

15
120
b) All:

int[] array = { 10, 20, 30 };

// Are all elements >= 10? YES
bool a = array.All(element => element >= 10);

// Are all elements >= 20? NO
bool b = array.All(element => element >= 20);

// Are all elements < 40? YES
bool c = array.All(element => element < 40);

Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);

Output

True
False
True
c) Any:

int[] array = { 1, 2, 3 };
// See if any elements are divisible by two.
bool b1 = array.Any(item => item % 2 == 0);
// See if any elements are greater than three.
bool b2 = array.Any(item => item > 3);
// See if any elements are 2.
bool b3 = array.Any(item => item == 2);
// Write results.
Console.WriteLine(b1);
Console.WriteLine(b2);
Console.WriteLine(b3);
Output

True
False
True
d) Average:

double[] array1 = { 1, 2, 3, 5, 0 };
double average1 = array1.Average();
Console.WriteLine(average1);
//
// Use Average to compute average string length.
//
string[] array2 = { "dog", "cat", "perls" };
double average2 = array2.Average(x => x.Length);
Console.WriteLine(average2);

Output

2.2
3.66666666666667
e) Count:

int[] array = { 1, 2, 3 };

// Don't use Count() like this! Use Length.
Console.WriteLine(array.Count());

List<int> list = new List<int>() { 1, 2, 3 };

// Don't use Count() like this! Use Count property.
Console.WriteLine(list.Count());

var result = from element in array
     orderby element descending
     select element;

// Good.
Console.WriteLine(result.Count());
Output
3
3
3
f) SequenceEqual:

string[] array1 = { "dot", "net", "perls" };
string[] array2 = { "a", "different", "array" };
string[] array3 = { "dot", "net", "perls" };
string[] array4 = { "DOT", "NET", "PERLS" };

bool a = array1.SequenceEqual(array2);
bool b = array1.SequenceEqual(array3);
bool c = array1.SequenceEqual(array4, StringComparer.OrdinalIgnoreCase);

Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Output

False
True
True
i) Sum:

int[] array1 = { 1, 3, 5, 7 };
List<int> list1 = new List<int>() { 1, 3, 5, 7 };

//
// Use Sum extension on their elements.
//
int sum1 = array1.Sum();
int sum2 = list1.Sum();

//
// Write results to screen.
//
Console.WriteLine(sum1);
Console.WriteLine(sum2);
Output
    (All element values were added together to get the result.)

16
16

5) Max and Min :

You can search a collection for its largest or smallest value. This is effective for many value types, such as strings and
numbers.

Max/Min

         int[] array1 = { 1, -1, -2, 0 };

        Console.WriteLine(array1.Max());
        Console.WriteLine(array1.Max(element => Math.Abs(element)));

       Console.WriteLine(array1.Min());
       Console.WriteLine(array1.Min(element => -element));

       Output

       1
       2
     -1
     -2

6) Enumerable :

The Enumerable type presents some static methods that can be useful in certain situations.

a) Empty:

         var empty = Enumerable.Empty<int>();
         Console.WriteLine(empty.Count());
         int[] array = empty.ToArray();
         Console.WriteLine(array.Length);
         Output

         0
         0
b) Repeat :

          var integers = Enumerable.Repeat(1, 10);
          foreach (int value in integers)
          Console.WriteLine(value);

         Output

          1
          1
          1
          1
          1

7) Query keywords :

Query expressions use a whole new set of keywords. These are contextual keywords. This means they only have meaning in query expressions. These query clauses are described in more detail.
  • ascending
  • descending
  • group
  • join
  • let
  • orderby
  • select new
They typically reduce performance. But LINQ methods and query expressions often improve the readability of C# programs. LINQ sometimes leads to new algorithmic approaches.