Implementing Sorting in Generic List (List<T>)
How to sort a generic list? Well, generic list provides a sort method itself in the form List<T>.Sort(). But wait a sec. This method requires you to implement sorting mechanism in your type. This is because this method uses default sorting mechanism. This is really simple, but what if you don't have sorting mechanism in your type? In that case this method throws InvalidOperationExpression.
List<T>.Sort() method uses the default comparer Comparer(T).Default for type T to determine the order of list elements. The Comparer(T).Default property checks whether type T implements the IComparable(T) generic interface and uses that implementation, if available. If not, Comparer(T).Default checks whether type T implements the IComparable interface. If type T does not implement either interface, Comparer(T).Default throws an InvalidOperationException.
If you use system types like String, default comparer works fine. This is because String class implements IComparable interface. If you see the definition of String class, it looks like (you can see this by pressing F12 keeping the cursor on the word 'String' in the code editor of visual studio):
public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>
But for types that does not implement Icomparable, default sort does not work. However there is one work around. This trick uses delegates.
To illustrate this example, I created a simple class Post. The code of this class is as below. This class does not implement IComparable interface. So default sort will not work for this.
using System; using System.Collections.Generic; using System.Linq; using System.Web;namespace Tyagi.Utility { public class Post : IComparable<Post> { public String Title { get; set; } public String Source { get; set; } } }
Create another class that will consume this class.
using System; using System.Collections.Generic; using System.Linq; using System.Web;namespace Tyagi.Utility { public class PostsList { List<Post> posts = new List<Post>();
<SPAN style="COLOR: blue">public </SPAN><SPAN style="COLOR: #2b91af">List</SPAN><<SPAN style="COLOR: #2b91af">Post</SPAN>> GelPosts() { posts.Add(<SPAN style="COLOR: blue">new </SPAN><SPAN style="COLOR: #2b91af">Post </SPAN>{ Title = <SPAN style="COLOR: #a31515">"MSN Space"</SPAN>, Source = <SPAN style="COLOR: #a31515">"Blog" </SPAN>}); posts.Add(<SPAN style="COLOR: blue">new </SPAN><SPAN style="COLOR: #2b91af">Post </SPAN>{ Title = <SPAN style="COLOR: #a31515">"CNBC TV 18"</SPAN>, Source = <SPAN style="COLOR: #a31515">"News" </SPAN>}); posts.Add(<SPAN style="COLOR: blue">new </SPAN><SPAN style="COLOR: #2b91af">Post </SPAN>{ Title = <SPAN style="COLOR: #a31515">"Independence Day"</SPAN>, Source = <SPAN style="COLOR: #a31515">"Movie" </SPAN>}); posts.Sort(<SPAN style="COLOR: blue">delegate</SPAN>(<SPAN style="COLOR: #2b91af">Post </SPAN>P1, <SPAN style="COLOR: #2b91af">Post </SPAN>P2) { <SPAN style="COLOR: blue">return </SPAN>P1.Title.CompareTo(P2.Title); }); <SPAN style="COLOR: blue">return </SPAN>posts; } }
}
The trick is in the use of a delegate in the call to Sort method of the posts object.
posts.Sort(delegate(Post P1, Post P2) { return P1.Title.CompareTo(P2.Title); });
The delegate accepts two parameter, both of the same class Post. It the uses the CompareTo method. This method is defined in the type of property. In this example, Title property of Post class is of type string. So the CompareTo method of string class will be called in this case. CompareTo method returns int. Sort method of List<T> uses this integer to compare two objects.
The above code returns list in the ascending order of title. To reverse the order, simply reverse the code as be below:
posts.Sort(delegate(Post P1, Post P2) { return P2.Title.CompareTo(P1.Title); });
This is one way. You can implement the sorting functionality in your class as well. I will discuss this in the next post.
12 Comments
Comments have been disabled for this content.
Shay Jacoby said
I would use lambda expressions like this: posts.Sort((x, y) => string.Compare(x.Title, y.Title));
derikwhittaker said
You could also just use the linq extension OrderBy and save yourself a bit of trouble of having to create a compare object. However, if you need fancy sorting then the linq extension may not be the right way to go.
Joe Chung said
LINQ would be fine for "fancy" sorting. see Shay's comment and replace .Sort with .OrderBy/.OrderByDescending.
Yanesh Tyagi said
@Shay Cool.. This will make code more readable. Thanks :) @derikwhittaker Linq extension orderby can be used only with the linq queries. Here I am talking about sorting the generic list. Anyways, thanks for sharing your thoughts.
Niki said
"Linq extension orderby can be used only with the linq queries. Here I am talking about sorting the generic list. Anyways, thanks for sharing your thoughts." Who says that? The Enumerable.OrderBy extension method works on any IEnumerable, that includes List.
Jason Plank said
Your example class "Post" implements IComparable in the write-up. It's a bit confusing.
Rajan said
above example is very useful for me.
Prem said
This really helped me to fix my issue with sorting. kudos to you !!!...........
Adam Kim said
I don't think you meant to derive class Post from IComparable. The way it is, you can't even get this to compile since you don't implement CompareTo.
Anup Pandey said
Nice Code!! Thanks
Rahan said
bad code.....Not fill my expectation
james said
how can I sort using two property ? first will be sort with ID , if ID is equal then sort with name.