Friday, 20 December 2013

LINQ Examples 3

Collection methods id LINQ

Collection methods

Using LINQ, you can modify existing collections, or collections created using other LINQ queries. LINQ provides you a set of functions that can be applied to collections. These functions can be grouped into the following types:
  • Set functions - functions that can be used for collection manipulation operations like merging, intersection, reverse ordering, etc.,
  • Element function - functions that can be used to take particular elements from collections,
  • Conversion functions - functions used to convert a type of collection to another,
  • Aggregation functions - SQL-like functions that enable you to find a maximum, sum, or average value of some field in collections,
  • Quantifier functions - used to quickly traverse through a collection.
These functions are described in the following sections.

Set functions

Set operators enable you to manipulate collections and use standard set operations like unions, intersects, etc. LINQ set operators are:
  • Distinct - used to extract distinct elements from a collection,
  • Union - creates a collection that represents the union of two existing collections,
  • Concat - add elements from one collection to another collection,
  • Intersect - creates a collection that contains elements that exist in both collections,
  • Except - creates a collection that contains elements that exist in one, but do not exist in another collection,
  • Reverse - creates a copy of a collection with elements in reversed order,
  • EquallAll - checks whether two collections have the same elements in the same order,
  • Take - this function takes a number of elements from one collection, and places them in a new collection,
  • Skip - this function skips a number of elements in a collection,
Assuming that the booksByTitle and filteredBooks collection are created in previous examples, the following code finds all books in booksByTitle that do not exist in filteredBooks, and reverses their order.
IEnumerable<Book> otherBooks = booksByTitle.Except(filteredBooks);            

otherBooks = otherBooks.Reverse();  

foreach (Book book in otherBooks)
   Console.WriteLine("Other book - {0} ",  book.Title);
In the following example, booksByTitle and filteredBooks are concatenated and the number of elements and number of distinct elements is shown.
IEnumerable<Book> mergedBooks = booksByTitle.Concat(filteredBooks);
Console.WriteLine("Number of elements in merged collection is {0}", mergedBooks.Count());
Console.WriteLine("Number of distinct elements in merged collection is {0}", mergedBooks.Distinct().Count());

Paging example

In this example is shown an example of client side paging using the Skip(int) and Take(int) methods. Assuming that there are ten books per page, the first three pages are skipped using Skip(30) (ten books per page placed on three pages), and all books that should be shown on the fourth page are taken using Take(10). An example code is:
IEnumerable<Book> page4 = booksByTitle.Skip(30).Take(10);            

foreach (Book book in page4)                
    Console.WriteLine("Fourth page - {0} ", book.Title);
There is also an interesting usage of the Skip/Take functions in the SkipWhile/TakeWhile form:
IEnumerable<Book> page1 = booksByTitle.OrderBy(book=>book.Price)            
                                      .SkipWhile(book=>book.Price<100)
                                      .TakeWhile(book=>book.Price<200);
foreach (Book book in page1)                
    Console.WriteLine("Medium price books - {0} ", book.Title);
In this example, books are ordered by price, all books with price less than 100 are skipped, and all books with price less than 200 are returned. This way all books with price between 100 and 200 are found.

Element functions

There are several useful functions that can be applied when you need to extract a particular element from a collection:
  • First - used to find the first element in a collection. Optionally you can pass a condition to this function in order to find the first element that satisfies the condition.
  • FirstOrDefault - used to find the first element in a collection. If that kind of element cannot be found, the default element for that type (e.g., 0 or null) is returned.
  • ElementAt - used to find the element at a specific position.
The following example shows the usage of the FirstOrDefault and ElementAt functions:
Book firstBook = books.FirstOrDefault(b=>b.Price>200);              
Book thirdBook = books.Where(b=>b.Price>200).ElementAt(2);
Note that you can apply functions either on the collection, or on the result of some other LINQ function.

Conversion functions

There are a few conversion functions that enable you to convert the type of one collection to another. Some of these functions are:
  • ToArray - used to convert elements of collection IEnumerable<T> to array of elements <T>.
  • ToList - used to convert elements of collection IEnumerable<T> to list List<T>.
  • ToDictionary - used to convert elements of a collection to a Dictionary. During conversion, keys and values must be specified.
  • OfType - used to extract the elements of the collection IEnumerable<T1> that implements the interface/class T2, and put them in the collection IEnumerable<T2>.
The following example shows the usage of the ToArray and ToList functions:
Book[] arrBooks = books.ToArray();
List<Book> lstBook = books.ToList();
ToDictionary is an interesting method that enables you to quickly index a list by some field. An example of such a kind of query is shown in the following listing:
Dictionary<string, Book> booksByISBN = books.ToDictionary(book => book.ISBN);
Dictionary<string, double> pricesByISBN = books.ToDictionary(    book => book.ISBN, 
                                book=>book.Price);
If you supply just one lambda expression, ToDictionary will use it as a key of new dictionary while the elements will be the objects. You can also supply lambda expressions for both key and value and create a custom dictionary. In the example above, we create a dictionary of books indexed by the ISBN key, and a dictionary of prices indexed by ISBN.

Quantifier functions

In each collection, you can find a number of logical functions that can be used to quickly travel through a collection and check for some condition. As an example, some of the functions you can use are:
  • Any - checks whether any of the elements in the collection satisfies a certain condition.
  • All - checks whether all elements in the collection satisfies a certain condition.
An example of usage of functions is shown in the following example:
if(list.Any(book=>book.Price<500)) 
    Console.WriteLine("At least one book is cheaper than 500$"); 

if(list.All(book=>book.Price<500))  
    Console.WriteLine("All books are cheaper than 500$");
In the example above, the All and Any functions will check whether the condition that price is less than 500 is satisfied for books in the list.

Aggregation functions

Aggregation functions enable you to perform aggregations on elements of a collection. Aggregation functions that can be used in LINQ are Count, Sum, Min, Max, etc.
The following example shows the simple usage of some aggregate functions applied to an array of integers:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

Console.WriteLine("Count of numbers greater than 5 is {0} ", numbers.Count( x=>x>5 ));
Console.WriteLine("Sum of even numbers is {0} ", numbers.Sum( x=>(x%2==0) ));
Console.WriteLine("Minimum odd number is {0} ", numbers.Min( x=>(x%2==1) ));
Console.WriteLine("Maximum is {0} ", numbers.Max());
Console.WriteLine("Average is {0} ", numbers.Average());
As you can see, you can use either standard aggregation functions, or you can preselect a subset using a lambda condition.

No comments:

Post a Comment