Alphanumeric sorting using LINQ

You can use PInvoke to get fast and good result:

class AlphanumericComparer : IComparer<string>
{
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    static extern int StrCmpLogicalW(string s1, string s2);

    public int Compare(string x, string y) => StrCmpLogicalW(x, y);
}

You can use it like AlphanumComparatorFast from the answer above.


That is because the default ordering for string is standard alpha numeric dictionary (lexicographic) ordering, and ABC11 will come before ABC2 because ordering always proceeds from left to right.

To get what you want, you need to pad the numeric portion in your order by clause, something like:

 var result = partNumbers.OrderBy(x => PadNumbers(x));

where PadNumbers could be defined as:

public static string PadNumbers(string input)
{
    return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}

This pads zeros for any number (or numbers) that appear in the input string so that OrderBy sees:

ABC0000000010
ABC0000000001
...
AB0000000011

The padding only happens on the key used for comparison. The original strings (without padding) are preserved in the result.

Note that this approach assumes a maximum number of digits for numbers in the input.


If you want to sort a list of objects by a specific property using LINQ and a custom comparer like the one by Dave Koelle you would do something like this:

...

items = items.OrderBy(x => x.property, new AlphanumComparator()).ToList();

...

You also have to alter Dave's class to inherit from System.Collections.Generic.IComparer<object> instead of the basic IComparer so the class signature becomes:

...

public class AlphanumComparator : System.Collections.Generic.IComparer<object>
{

    ...

Personally, I prefer the implementation by James McCormack because it implements IDisposable, though my benchmarking shows that it is slightly slower.

Tags:

C#

Linq

Sorting