Easiest method to OrderBy a String using StringComparison.Ordinal
Asked Answered
G

3

7

I've found a bug (in my code) that results from String.CompareTo and binary search because my custom IComparer (for the wrapping type) uses String.Compare(x, y, StringComparison.Ordinal).

This is because items.OrderBy(i => i.Name) (where Name is of type string) used to build the Array to search used the string object itself as the IComparable - and such has different rules:

The comparison uses the current culture to obtain culture-specific information such as casing rules and the alphabetic order of individual characters. For example, a culture could specify that certain combinations of characters be treated as a single character, or uppercase and lowercase characters be compared in a particular way, or that the sorting order of a character depends on the characters that precede or follow it.

For example, {A, b, C} is sorted as [A, b, C] with the OrderBy-using-Default-String-Compare but should be [b, A, C] per the Ordinal comparison - since it is not, the binary search is failing.

Now, with the "context" out of the way,

What is the easiest (eg. without implementing a custom IComparer for strings) way to order the objects with string properties the same as with String.Compare(.., StringComparison.Ordinal)?


Edit: I [just realized I] can, and probably should, just use OrderBy(x => x, theSameComparer) - but supposing this wasn't possible, how can OrderBy be used with the same results?

Geostrophic answered 20/2, 2015 at 21:41 Comment(0)
K
15

There is a pre-built StringComparer that applies StringComparison.Ordinal - that's StringComparer.Ordinal:

items.OrderBy(i => i.Name, StringComparer.Ordinal)
Kossuth answered 20/2, 2015 at 21:48 Comment(2)
Ah, brilliant (or makes me seem dull): I assumed StringComparer.Ordinal was a constant - should have realized it was itself a comparer.Geostrophic
Ah, should of refreshed the page. You beat me to it.Did
D
2

You should be able to add StringComparer.Ordinal directly into your OrderBy.

string[] content = { "A", "b", "C", "d", "AB", "Ab" };
var ordered = content.OrderBy(o => o, StringComparer.Ordinal);

Then once you iterate through ordered you would receive the following output:

// Output:
A
AB
Ab
C
b
d

I believe that is what your after.

Did answered 20/2, 2015 at 21:54 Comment(0)
C
2

It worth mentioning, it can be used in Array and List sorting as well not just in Linq:

string[] content = { "A", "b", "C", "d", "AB", "Ab" };
Array.Sort(content);
//output: A,Ab,AB,b,C,d
Array.Sort(content, StringComparer.Ordinal);
//output: A,AB,Ab,C,b,d

var list = new List<string>{ "A", "b", "C", "d", "AB", "Ab" };
list.Sort(StringComparer.Ordinal);
//output: the same as array.srot and linq with Ordinal comparer
Cognize answered 21/6, 2021 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.