LINQ and OrderBy

Sep 28, 2016  

I needed to order a collection of properties in C# and I immediately grabbed for LINQ:

var result = items.OrderBy (x => x.Name);

I was surprised to see that the default comparer used by OrderBy, when applied to strings, is case insensitive: given a, B, c the code produces a, B, c as the sorted result.

In my case, I needed to apply an ordinal sort. What I really want is B, a, c (B has ASCII code 66 and a has ASCII code 97).

IComparer<string>

OrderBy() comes with an overload, which takes an IComparer<T> as its second argument. However, having to implement a comparer like this one is overkill:

internal sealed class NameComparer : IComparer<string>
{
    public static readonly NameComparer Instance = new NameComparer();

    public int Compare(string x, string y)
    {
        int length = Math.Min (x.Length, y.Length);
        for (int i = 0; i < length; ++i) {
            if (x[i] == y[i]) continue;
            return x[i].CompareTo (y[i]);
        }

        return x.Length - y.Length;
    }
}

There are already multiple comparers in System.StringComparer:

  • Ordinal, OrdinalIgnoreCase → ordinal comparisons.
  • CurrentCulture, CurrentCultureIgnoreCase → comparisons based on the current culture.

So finally, my code looks like this:

var result = items.OrderBy (x => x.Name, System.StringComparer.Ordinal);

Thanks to Brian Gerspacher who pointed me to this solution.