sitemap

Custom sorting order in LINQ (ORDER BY WEIGHTING)

I have developed a C# LINQ extension method to allow very flexible ordering by assigning weightings to the sort keys of the elements to be ordered. I was inspired by the functionality offered by SQL Server’s ORDER BY CASE WHEN:

ORDER BY
CASE SEASON
    WHEN 'WINTER' THEN 1
    WHEN 'SPRING' THEN 2
    WHEN 'SUMMER' THEN 3
    WHEN 'AUTUMN' THEN 4
END

The extension method I have created lets you pass a lambda function which allows the use of logic to apply custom weightings to the sort keys.

var data = dt.Select(g => new
{
    Season = g.season,
    AverageTemp = g.temp
}).OrderByWeight(a => a.Season, x =>
{
    if (x == "WINTER") return 1;
    if (x == "SPRING") return 2;
    if (x == "SUMMER") return 3;
    if (x == "AUTUMN") return 4;
    return 99;
});

The above will return an IOrderedEnumerable sorted by Season in the order WINTER, SPRING, SUMMER, AUTUMN. However, the OrderByWeight extension method provides even more powerful functionality as the lambda allows us to perform string comparisons and more:

var data = dt.Select(g => new
{
    Year = g.year,
}).OrderByWeight(a => a.Year, x =>
{
    if (x.Contains("2008")) return 1;
    if (x.Contains("2009")) return 2;
    if (x.Contains("2010") return 3;
    return 99;
});

Using the above, a non-trivial list such as {‘London 2010′, ‘Leeds 2008′, ‘Cardiff 2009′, ‘Glasgow 2011′} can be easily sorted to {‘Leeds 2008′, ‘Cardiff 2009′, ‘London 2010′, ‘Glasgow 2011′}

The extension method used to implement this functionality is:

public static IOrderedEnumerable<TSource> OrderByWeight<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, int> weighting) where TKey : IComparable
{
    Dictionary<TSource, int> order = new Dictionary<TSource, int>();
    foreach (TSource item in source)
    {
        if (!order.ContainsKey(item)) order.Add(item, weighting(keySelector(item)));
    }
    return source.OrderBy(s => order[s]);
}

It has not been throughly unit tested yet but it should have the same behaviour as GroupBy. Whilst I have only provided the C# implementation I’m sure it can be converted to other languages using the CLR.


Posted by Daniel Skinner 2009-03-18 15:10:18


Trackback Button Comments RSS 2.0 Button

Categories: General

Tags: ,

4 Comments »

  1. Dude, you are cool!

    I just used this in my code, and it works really nice.
    Very nice.

    Comment by R.B — April 28, 2009 @ 5:49 pm

  2. I’m glad it was useful. I have used it many times since initially writing it.

    Comment by Daniel Skinner — April 28, 2009 @ 6:06 pm

  3. This is brilliant. Thank you!

    Comment by Dave Gruska — October 2, 2009 @ 7:15 pm

  4. Nice code, it worked like needed

    Comment by Supersum — October 30, 2009 @ 12:32 am

RSS feed for comments on this post. TrackBack URL

Leave a comment