Tutorial: Refresher on Sorting Generics in C# – IComparable & IComparer

by Max Slabyak

I thought I’d post a quick refresher for sorting Lists<> and generics since it will be used in the post about working with Sitecore Fast Query.

There are a lot of ways of sorting items you get back from Sitecore, including even implementing a bubble sort in the code-behind aspx.cs file.  That may work for a quick prototyping exercise; however, when working with enterprise class systems, why not leverage the tools C# gave you to create elegant and robust code by creating line-of-business model objects and using a C# List<T> that already comes with sort functionality (provided you define the rules on how to compare your objects)?

IComparable

If you want to your objects to be sortable, you have to make sure they implement the IComparable method, otherwise when you try to do a List<T>.Sort() on them, you will get an exception.  To implement the IComparable class, you will need to implement the CompareTo() method, which essentially describes how to compare two objects.  If you compare your objects alphabetically, you can take advantage of the String.CompareTo() method here.  Take a look at the code example below using a Movie object.

public class Movie : IComparable
{
public int YearReleased { get; set; }
public string MovieTitle { get; set; }

//need to implement this as a result
//of declaring the IComparable interface
int CompareTo(Movie otherMovie)
{
return MovieTitle.CompareTo(otherMovie.Title);
}
}

IComparer

When you implement the IComparable interface and the CompareTo method, that is the default sort method.  When you want to create additional properties on which to sort, this is where the IComparer interface comes in.   For every method on which you will want to sort, you will have to create a class that implements the IComparer interface.  So, if you wanted to create two sorts – ascending and descending – on the year the movie was released, you will need two classes that implement the IComparer interface.  With this particular example, we can create these classes as nested.

public class Movie : IComparable //main class
{
public int YearReleased { get; set; }
public string MovieTitle { get; set; }

public class SortByYearReleasedAscending : IComparer
{
int Compare(Movie a, Movie b)
{
var compareResult = a.YearReleased - b.YearReleased;

return ( (compareResult == 0) ? 0 : compareResult / Math.Abs(compareResult) );

}
}

public class SortByYearReleasedDescending : IComparer
{
}
}

In case I lost you in the Compare() method, I am all about C# shortcuts (thanks to ReSharper) and didn’t feel like writing this out:

if (a.year > b.year)
return 1;
if (a.year < b.year)
return -1;
else
return 0;

Since the year is an integer, we can just take the difference. If the value on the left is bigger, the result will be positive, otherwise negative. At that point, we will need to return 1, -1, or if it’s the same, the result is 0. To get our result down to a 1 (positive or negative), we simply divide by the absolute value of the result, but not before we check if it’s 0 to bypass the divide by zero error.

And that’s all there is to it. To piece it all together, if you have a List<movieList>, you can do a sort on it using movieList.Sort() which will use the default IComparable.CompareTo method, or you can specify how you want it sorted by passing in the IComparer component, like movieList.Sort(new movieList.SortByYearReleasedAscending())

Questions or comments – drop me a line.

Share

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>