views:

511

answers:

2

To sort a List on multiple criteria, I'm currently doing something like:

collection.Sort((f1, f2) =>
{
    var comp = f1.FirstCriteria.CompareTo(f2.FirstCriteria);
    return comp != 0 ? comp : f1.SecondCriteria.CompareTo(f2. SecondCriteria);
});

But wouldn't it be nice to be able to do something like:

collection.MultipleSort(f1.FirstCriteria, f2.FirstCriteria)
          .Then(f1.SecondCriteria, f2.SecondCriteria)

Any ideas for a good implementation of a fluent interface for sorting?

+8  A: 

You mean something like the following?

using System.Linq;

collection.OrderBy(t => t.FirstCriteria).ThenBy(t => t.SecondCriteria);
Greg Beech
Now why didn't google bring that one up! :-) I should read more books before asking questions!
Hainesy
The only question would then be how to do descending?
Hainesy
@Hainsey, How about OrderByDescending and ThenByDescending?
LukeH
@Hainsey, I wouldn't worry about missing it too much. To me Linq extensions aren't always the most discoverable things. But the nice thing is, once you discover it, you don't forget it :>
billb
+2  A: 

The problem here is that it sounds like you want to do an in place sort; in which case, you'd need to know (with a fluent API) when you've finished adding conditions. This contrasts to the LINQ approach, because that uses deferred execution.

For single condition sorts, you can use something like:

public static void Sort<TSource, TValue>(this List<TSource> source,
        Func<TSource, TValue> selector) {
    var comparer = Comparer<TValue>.Default;
    source.Sort((x,y)=>comparer.Compare(selector(x),selector(y)));
}
public static void SortDescending<TSource, TValue>(this List<TSource> source,
        Func<TSource, TValue> selector) {
    var comparer = Comparer<TValue>.Default;
    source.Sort((x,y)=>comparer.Compare(selector(y),selector(x)));
}

It would be harder with multiple sorts; you can't use params because each TValue may be different. You'd probably need to either use a terminator step and an intermediary "builder" class (essentially writing a DSL), or you'd need to construct the comparer separately first.

Marc Gravell