Custom Sorting With IComparable and IComparer

Sometimes, you want to be able to sort objects on a number of different fields. For example, employees can be sorted by their name, years of service, pay rate; or blog posts by the date they were posted, their status, number of comments, the author. It's really easy to offer all these sorting methods. Best of all you don't have to write too much code.

Default Sorting

Suppose we have a Politician class:


public class Politician
{
private string ssn;
private string name;
private int powerIndex;
private int voterBaseIndex;
private int suckitudeIndex;

public string SSN
{
get { return this.ssn; }
}

public string Name
{
get { return this.name; }
}

public int PowerIndex
{
get { return this.powerIndex; }
}

public int VoterBaseIndex
{
get { return this.voterBaseIndex; }
}

public int SuckitudeIndex
{
get { return this.suckitudeIndex; }
}
}

We want to allow the users to sort by name, powerIndex, voterBaseIndex, or the suckitudeIndex. We feel that people generally want to sort the politicians by their suckitudeIndex. So we're going to have the default sorting method sort by the suckitudeIndex while giving users the option of sorting by various other indices, too.

Default Sorting: IComparable

To tell .NET how to sort objects by default, all we need to do is inherit from the IComparable interface:

public class Politician : System.IComparable<Politician>

You notice that we're using the generic interface, which takes in an object of the type we're interested in, instead of the normal IComparable interface, which takes in whatever object.

The IComparable interface has a single method that we need to implement: CompareTo; the implementation is straight-forward:


public int CompareTo(Politician politician)
{
// NULL is considered to be smaller than
// any other value.
if (politician == null)
{
return 1;
}

else if (this.suckitudeIndex < politician.suckitudeIndex)
{
return -1;
}

else if (this.suckitudeIndex == politician.suckitudeIndex)
{
return 0;
}

else { return 1;
}
}

Sorting by Power Index: IComparer

A class can sort by any number of fields or any combination of fields. We do this by creating classes that implement the IComparer.

For example:


public class PowerIndexComparer : System.Collections.Generic.IComparer<Politician>
{
public int Compare(Politician first, Politician second)
{
if (first == null & second == null)
{
return 0;
}

else if (first == null)
{
return -1;
}

else if (second == null)
{
return 1;
}

else if (first.powerIndex < second.powerIndex)
{
return -1;
}

else if (first.powerIndex == second.powerIndex)
{
return 0;
}

else { return 1;
}
}
}

And when you want to sort politicians by the power index, simply pass along the IComparable object to the sort method:

politicians.Sort(new PowerIndexComparer());

Usually, I create the IComparable classes as private classes within the main class. For example, the PowerIndexComparer would be declared as a private class within the Politician class. This was how I saw it done in one of the books I read. It makes sense, because all comparer classes aren't independent/full-fledged classes but rather part of the Politician class. So the way this would work:


public class Politician : System.IComparable<Politician>
{
private class PowerIndexComparer : System.Collections.Generic.IComparer<Politician>

{
public int Compare(Politician first, Politician second)
{
if (first == null & second == null)
{
return 0;
}

else if (first == null)
{
return -1;
}

else if (second == null)
{
return 1;
}

else if (first.powerIndex < second.powerIndex)
{
return -1;
}

else if (first.powerIndex == second.powerIndex)
{
return 0;
}

else { return 1;
}
}
}

public static System.Collections.Generic.IComparer<Politician> PowerIndexSorter
{
get { return new PowerIndexComparer(); }
}
}

So when you want to sort by power index:

politicians.Sort(Politician.PowerIndexSorter);
Original article here
By Sadhana G   Popularity  (15587 Views)