OrderBy Operator Part 13
OrderBy is one of the ordering query operators available in linq. In terms of availability, you can use OrderBy query operator with linq to objects, linq to SQL and linq to XML. Unlike many query operators that are only available in method or dot syntax, OrderBy query operator can also be used in query syntax which is sometimes easier to use than method syntax.
The first prototype for OrderBy operator that we will look is as follows.
public static IOrderedEnumerable<T> OrderBy<T, K>(
this IEnumerable<T> source,
Func<T, K> keySelector) where K : IComparable<K>;
From the above prototype, we can see that OrderBy is an extension method that is available on any object that implements IEnumerable<T>. OrderBy operator allows the source sequence to be ordered in ascending order based on the key returned by the keySelector delegate. The key selector delegate gets executed on every element of type T when source sequence gets enumerated. The keySelector delegate returns an element of type K. Type K can be same as T or it can be different. The OrderBy extension method also enforces a constraint that the type of element returned from the keySelector delegate must implement IComparable interface. The reason for that is because, this is how OrderBy operator compares if two elements are same by calling its compareTo method. Looking at the prototype above you will also notice that OrderBy operator returns a collection of IOrderedEnumerable<T>. Therefore if you want to sort again by another key value, you cannot subsequently use OrderBy query operator again since OrderBy query operator requires the collection to implement IEnumerable<T> instead of IOrderedEnumerable<T>. So if you need to sort again you have to use thenby query operator which can be used on collections that implement IOrderedEnumerable<T> and returns a collection that also implements IOrderedEnumerable<T>.
Let's see an example of sorting a collection of strings in ascending order, both in method and dot syntax.
In the above example I am simply ordering a collection of string passing in a lambda expression that evaluates to a string key. Using that key, the collection gets sorted in ascending order. Since OrderBy operator is also available in query syntax, I am also showing the same code in query syntax which gives the same output as shown in the output screen shot.
Let's move forward with a little more different example where we are sorting complex objects and where the elements in the input sequence is not of the same type that is returned by the keySelector delegates. In the above example the collection that we were sorting was of type string and the keySelector delegate was also returning the key that was also string. In the next example I will demonstrate how you can use OrderBy to sort complex objects and that the type returned by the keySelector delegate does not have to be the same type as the input sequence.
In the above example I am using a complex type Person which has two properties, ID and Name. I am then ordering person object based on its ID which is an integer type. I am also showing the same code using the query syntax as well.
What if you want to order the collection using multiple columns or properties? As I have mentioned previously that OrderBy query operator requires input sequence to implement IEnumerable<T> where as the returned collection from OrderBy query operator is IOrderedEnumerable<T>. Therefore you have to use thenby operator to further sort your objects. Let's look at a simple example of that.
I have modified the example slightly where it sorts first based on ID property and than sorts the collection based on Name. Notice that in method syntax I am making use of ThenBy operator to sort the collection second time by Name. The same 2 level sorting is easily accomplished in query syntax by simply appending the additional property with comma preceding it.
So far we have looked at examples of using OrderBy operator with linq to objects, now we will see a simple example of using OrderBy operator with linq to XML.
In the above example I am making use of OrderBy operator with linq to XML queries. I demonstrate the example using both method and query syntax. Notice how I am casting the element to the correct type to gets its value that is used as the keySelector delegate for the OrderBy operator.
Since IQueryable<T> also defines implementation for OrderBy operator we can use OrderBy operator in linq to SQL queries. Linq to SQL converts the OrderBy operator into OrderBy operator that SQL server can understand. Let's look at an example of using OrderBy with Northwind database.
In the above example, I am making use of OrderBy operator with linq to SQL query that gets converted to OrderBy query operator in SQL server. Notice that I am first ordering by computed value which is defined by another lambda expression that sums up all the freight charges for all the orders of a particular customer. I then sort my collection using the contact name.
OrderBy operator forces an immediate execution of query for linq to object and XML. It is important that you understand that the query is not differed because the entire collection needs be enumerated before ordering is possible. This can have a negative impact when the collection is huge as in the example below.
The above code takes forever to execute despite the fact Take operator uses differed execution plan to only retrieve first 5 integers. The problem is the OrderBy operator which requires the entire collection to be created and enumerated, hence causing the entire query to get executed immediately.
Although OrderBy operator uses default comparer, you also have the option of passing in a custom comparer to comapre two elements in a collection. In the case of linq to SQL, you cannot use a custom comparer because in SQL server there is no concept of custom sort and all you can do is sort by computed value or column in a database. Using a custom comparer in linq to SQL query would cause a runtime exception. Let's look at a simple example of using a custom comparer.
In the above example, I make use of out of the box comparer that allows me to sort elements without considering the casing of the names with in the collection. I pass that comparer in the second overloaded version of the OrderBy query operator. Also notice that lower case paul came first and than upper case Paul followed. This is the same ordering that was present in the original collection. Although the OrderBy operator preserved the original ordering, it is not guaranteed that the original ordering would be adhered if two elements have the same key returned by the key selector. Only ordering that is guaranteed is what is returned as a key by the key selector delegate.