How can you do custom sorting in LINQ with null always on the end?

I need to sort in memory lists of strings or numbers in ascending or descending order. However, the list can contain null values and all null values must appear after the numbers or strings.

That is the input data might be:

1, 100, null, 5, 32.3

The ascending result would be

1, 5, 32.3, 100, null

The descending list would be

100, 32.3, 5, 1, null

Any ideas on how to make this work?

Answers


I don't have a compiler in front of me to check, but I'm thinking something like:

x.OrderBy(i => i == null).ThenBy(i => i)

You can write your own comparer which delegates to an existing one for non-nulls, but always sorts nulls at the end. Something like this:

public class NullsLastComparer<T> : IComparer<T>
{
    private readonly IComparer<T> proxy;

    public NullsLastComparer(IComparer<T> proxy)
    {
        this.proxy = proxy;
    }

    public override int Compare(T first, T second)
    {
        if (first == null && second == null)
        {
            return 0;
        }
        if (first == null)
        {
            return 1;
        }
        if (second == null)
        {
            return -1;
        }
        return proxy.Compare(first, second);
    }
}

EDIT: A few issues with this approach:

Firstly, it doesn't play nicely with anonymous types; you might need a separate extension method to make that work well. Or use Ken's answer :)

More importantly, it violates the IComparer<T> contract, which specifies that nulls should be first. Now personally, I think this is a mistake in the IComparer<T> specification - it should perhaps define that the comparer should handle nulls, but it should not specify whether they come first or last... it makes requirements like this (which are perfectly reasonable) impossible to fulfil as cleanly as we might want, and has all kinds of awkward ramifications for things like a reversing comparer. You'd expect such a thing to completely reverse the ordering, but according to the spec it should still maintain nulls at the start :(

I don't think I've seen any .NET sorting implementations which actually rely on this, but it's definitely worth being aware of.


As Jon said, you need to define your custom Comparer, implementing IComparer. Here's how your Compare method in the custom comparer would like that can keep null at the end.

    public int Compare(Object x, Object y)
    {
        int retVal = 0;

        IComparable valX = x as IComparable;
        IComparable valY = y as IComparable;

        if (valX == null && valY == null)
        {
            return 0;
        }

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

        return valX.CompareTo(valY);
    }

Need Your Help

confusion over access control declaration for variable and the class enclosing the varaible

xcode swift class variables access-control

The code below is legal in Swift, however, I was just wondering why class Something is not forced to be declared private. The reason why I'm saying that is because one of its variable, private var

How can I make the modal popup scroll its contents with the page?

asp.net ajaxcontroltoolkit modalpopupextender sizing

I've got a modal popup and when it loads contents that are taller than the browser height I am unable to scroll down to view the rest of the information. Instead the background can scroll but the ...