Home > c# > A Simple IComparer Decorator to Add Sort Ordering

A Simple IComparer Decorator to Add Sort Ordering

Today I needed to implement some sorting over domain objects based on the following rules:

  • Surveys must be sorted by their age (effective date – generally the date the survey was created)
  • Priority surveys must appear at the top of the list

So I set out an encapsulated these rules into a nice class that implemented IComparer<T>. The single method of this interface int Compare(T x, T y) should return an integer according to the following rules:

  • If x is less than y, return an int less than 0
  • If x is equal to y, return 0
  • If x is greater than y, return an int greater than 0

Writing this up, we end up with a pretty simple encapsulation of the comparison rules than make pretty good sense:

// Priority > Normal
if (left.IsPriority != right.IsPriority)
{
    if (left.IsPriority)
        return 1;
    else
        return -1;
}

// Older Effective Date > Newer Effective Date
if(left.EffectiveDate > right.EffectiveDate)
{
    return -1;
}

if(left.EffectiveDate < right.EffectiveDate)
{
    return 1;
}

return 0;
The problem is, when I view the sorted result, my priority surveys are at the bottom of the list, a bit of digging and I find out that by default List<T>.Sort(IComparer<T>) returns the list sorted in descending order.

I could correct this by simply changing the returned values to return the inverse of the value (i.e. 1 becomes -1 and vice versa), however that would distort the meaning of the comparison (priority survey > normal survey and older survey > newer survey). A better approach is to add the sort ordering after the comparison, even better, we can completely separate the ordering from the comparison by decorating the comparer with another class that implements the sort ordering logic. This leads to the SortOrderComparer<T> shown below:

public enum CompareSortOrder
{
    Descending,
    Ascending
}

public class SortOrderComparer<TEntity> : IComparer<TEntity>
{
    private readonly IComparer<TEntity> _innerComparer;
    private readonly CompareSortOrder _sortOrder;

    public SortOrderComparer( IComparer<TEntity> innerComparer, CompareSortOrder sortOrder )
    {
        _innerComparer = innerComparer;
        _sortOrder = sortOrder;
    }

    public int Compare( TEntity x, TEntity y )
    {
        int result = _innerComparer.Compare( x, y );
        if(_sortOrder == CompareSortOrder.Descending)
        {
            return result;
        }

        return result * -1;
    }
}
Now we can apply sort ordering to any comparer quickly and simply:

IComparer<MyClass> sortingComparer = new SortOrderComparer( new MyComparer(), CompareSortOrder.Ascending );
list.Sort( sortingComparer );
I wouldn’t be surprised if this has been done somewhere else as it is reasonably obvious (only took me a few days to see it!) :) .

Advertisement
Categories: c#
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

Please log in to WordPress.com to post a comment to your blog.

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.