linqsortinglinq-to-objectscase-sensitive

LINQ and CASE Sensitivity


I have this LINQ Query:

TempRecordList = new ArrayList(TempRecordList.Cast<string>().OrderBy(s => s.Substring(9, 30)).ToArray());

It works great and performs sorting in a way that's accurate but a little different from what I want. Among the the result of the query I see something like this:

Palm-Bouter, Peter
Palmer-Johnson, Sean

Whereas what I really need is to have names sorted like this:

Palmer-Johnson, Sean
Palm-Bouter, Peter

Basically I want the '-' character to be treated as being lower than the character so that names that contain it show up later in an ascending search.

Here is another example. I get:

Dias, Reginald
DiBlackley, Anton

Instead of:

DiBlackley, Anton
Dias, Reginald

As you can see, again, the order is switched due to how the uppercase letter 'B' is treated.

So my question is, what do I need to change in my LINQ query to make it return results in the order I specified. Any feedback would be greatly appreaciated.

By the way, I tried using s.Substring(9, 30).ToLower() but that didn't help.

Thank you!


Solution

  • To customize the sorting order you will need to create a comparer class that implements IComparer<string> interface. The OrderBy() method takes comparer as second parameter.

    internal sealed class NameComparer : IComparer<string> {
        private static readonly NameComparer DefaultInstance = new NameComparer();
    
        static NameComparer() { }
        private NameComparer() { }
    
        public static NameComparer Default {
            get { return DefaultInstance; }
        }
    
        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;
                if (x[i] == '-') return 1;
                if (y[i] == '-') return -1;
                return x[i].CompareTo(y[i]);
            }
    
            return x.Length - y.Length;
        }
    }
    

    This works at least with the following test cases:

    var names = new[] {
        "Palmer-Johnson, Sean",
        "Palm-Bouter, Peter",
        "Dias, Reginald",
        "DiBlackley, Anton",
    };
    
    var sorted = names.OrderBy(name => name, NameComparer.Default).ToList();
    
    // sorted:
    // [0]: "DiBlackley, Anton"
    // [1]: "Dias, Reginald"
    // [2]: "Palmer-Johnson, Sean"
    // [3]: "Palm-Bouter, Peter"