If you've ever wanted to sort a list of objects using more than one comparer (i.e., you want to sort a list of people by last name and then by first name), then you probably had to compose your own IComparer object to do so. If you wanted to be able to dynamically change sort orders, then your task was more difficult.
To address this problem, I wrote a class called ComparerProxy which implements IComparer and proxies comparisons through a list of IComparers. First, I'll show you the class and then I'll explain a few nuances.
public class ComparerProxy<T> : IComparer<T>So, what's happening here is that when ComparerProxy.Compare() is called, it loops through the collection of comparers until it either runs out of comparers and deems the two objects equal or it identifies a difference and returns the value of that difference.
{
private readonly IComparer<T>[] _comparers;
public ComparerProxy(params IComparer<T>[] comparers)
{
_comparers = comparers;
}
public int Compare(T x, T y)
{
int retVal = 0, i = 0;
while (retVal == 0 && i < _comparers.Length)
retVal = _comparers[i++].Compare(x, y);
return retVal;
}
}
That sounds confusing even to me and I wrote the class so I'll break it down. Basically, imagine you have a Person object (and soon we will). The person has a FirstName property and a LastName property. If you want to sort by LastName and then by FirstName, it would go something like this:
- Sort the two objects by LastName
- If the two objects have the same LastName, then sort by FirstName
- If the two objects have the same FirstName, then the two objects are equal
So, shall we see what it does? I created a Person class (very similar do the one described above) just to do some testing. I overrode the ToString method to print "Last, First" and I added two IComparers. Here's what that class looks like:
private class PersonI created a test list of Persons and a set of IComparers to test with including two complex IComparers using the ComparerProxy:
{
public string First, Last;
public class FirstNameComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.First.CompareTo(y.First);
}
}
public class LastNameComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Last.CompareTo(y.Last);
}
}
public override string ToString()
{
return string.Format("{0}, {1}", Last, First);
}
}
List<Person> _folks = new List<Person>();I executed the following lines and, lo and behold, achieved the expected results:
_folks.Add(new Person { First = "Jennifer", Last = "Caldwell" });
_folks.Add(new Person { First = "Cory", Last = "Caldwell" });
_folks.Add(new Person { First = "Lauren", Last = "Woody" });
_folks.Add(new Person { First = "Colin", Last = "Caldwell" });
_folks.Add(new Person { First = "Jamus", Last = "Brechtel" });
_folks.Add(new Person { First = "Pete", Last = "Woody" });
_folks.Add(new Person { First = "Royce Ann", Last = "Woody" });
_folks.Add(new Person { First = "Ashley", Last = "Brechtel" });
IComparer<Person> first = new Person.FirstNameComparer();
IComparer<Person> last = new Person.LastNameComparer();
IComparer<Person> firstLast = new ComparerProxy<Person>(first, last);
IComparer<Person> lastFirst = new ComparerProxy<Person>(last, first);
_folks.Sort(last);
PrintList(_folks);
// Brechtel, Jamus
// Brechtel, Ashley
// Caldwell, Jennifer
// Caldwell, Colin
// Caldwell, Cory
// Woody, Lauren
// Woody, Royce Ann
// Woody, Pete
_folks.Sort(first);
PrintList(_folks);
// Brechtel, Ashley
// Caldwell, Colin
// Caldwell, Cory
// Brechtel, Jamus
// Caldwell, Jennifer
// Woody, Lauren
// Woody, Pete
// Woody, Royce Ann
_folks.Sort(firstLast);
PrintList(_folks);
// this one is the same as just sorting by first name
// in retrospect, I should've added some folks with the same first name
// c'est la vie
//
// Brechtel, Ashley
// Caldwell, Colin
// Caldwell, Cory
// Brechtel, Jamus
// Caldwell, Jennifer
// Woody, Lauren
// Woody, Pete
// Woody, Royce Ann
_folks.Sort(lastFirst);
PrintList(_folks);
// Brechtel, Ashley
// Brechtel, Jamus
// Caldwell, Colin
// Caldwell, Cory
// Caldwell, Jennifer
// Woody, Lauren
// Woody, Pete
// Woody, Royce Ann
No comments:
Post a Comment