Я пытаюсь отсортировать последовательность букв с помощью оператора LINQ Order и не получаю ожидаемого результата. Я ожидал, что передача StringComparer.CurrentCulture приведет к другому порядку, чем передача StringComparer.CurrentCultureIgnoreCase, но оба, похоже, игнорируют регистр моих букв:
string[] letters = ["y", "X", "Z"];
Console.WriteLine(String.Join(", ", letters.Order(StringComparer.CurrentCulture)));
Console.WriteLine(String.Join(", ", letters.Order(StringComparer.CurrentCultureIgnoreCase)));
Выход:
X, y, Z
X, y, Z
Онлайн-демо.
Я ожидал, что CurrentCulture будет чувствителен к регистру букв и будет давать следующий порядок: X, Z, y, потому что маленькие английские буквы находятся дальше в таблице ASCII, чем заглавные английские буквы. Что я не правильно понимаю?
@Progman Ах, значит, они чувствительны друг к другу (x <X, y < Y и т. д.), но не к другим буквам?





Разница между StringComparer.CurrentCulture и StringComparer.CurrentCultureIgnoreCase актуальна, когда у вас есть два значения, которые имеют «одну и ту же» строку/текст, но могут иметь разные регистры. В вашем примере ["y", "X", "Z"] все строки «разные», поскольку «x» по-прежнему предшествует «y», а «y» по-прежнему предшествует «z». И это не имеет никакого отношения к случаям этих строк.
Но когда алгоритм сортировки видит список типа ["x", "X", "X", "x", "x", "X"], существует разница, должны ли значения "x" и "X" быть одинаковыми в отношении сортировки (поэтому метод Compare() возвращает 0) или они должны быть разными (поэтому метод Compare() вернет -1/1 или любое другое значение меньше/больше нуля).
Когда вы используете следующий код:
string[] letters = ["y", "X", "Z", "X", "x", "y", "Y", "z", "Z", "y", "Y", "z", "Z"];
Console.WriteLine(String.Join(", ", letters.Order(StringComparer.CurrentCulture)));
Console.WriteLine(String.Join(", ", letters.Order(StringComparer.CurrentCultureIgnoreCase)));
вы получите следующий результат:
x, X, X, y, y, y, Y, Y, z, z, Z, Z, Z
X, X, x, y, y, Y, y, Y, Z, z, Z, z, Z
Во второй строке все «одинаковые» буквы равны между собой, регистр буквально игнорируется, как указано. А поскольку алгоритм сортировки стабилен, относительный порядок «одних и тех же» букв все еще находится в том же исходном порядке (здесь на букве «у»):
["y", "X", "Z", "X", "x", "y", "Y", "z", "Z", "y", "Y", "z", "Z"]
^ ^ ^ ^ ^
1 2 3 4 5
X, X, x, y, y, Y, y, Y, Z, z, Z, z, Z
^ ^ ^ ^ ^
1 2 3 4 5
Спасибо, теперь это имеет смысл. Однако я был очень озадачен, когда увидел такое поведение.
Насколько я понимаю, это происходит потому, что эти сравнители выполняют лингвистические сравнения:
Это лингвистическое сравнение иногда называют «порядком сортировки слов».
И вы ожидали обычного.
Из документации:
Вы сравниваете строки, чтобы ответить на один из двух вопросов: «Эти две строки равны?» или «В каком порядке следует располагать эти строки при их сортировке?»
Эти два вопроса осложняются факторами, влияющими на сравнение строк:
- Вы можете выбрать порядковое или лингвистическое сравнение.
- Вы можете выбрать, если случай имеет значение.
- Вы можете выбрать сравнения, специфичные для конкретной культуры.
- Лингвистические сравнения зависят от культуры и платформы.
Поля перечисления
System.StringComparisonпредставляют следующие варианты:
CurrentCulture: Сравнивайте строки, используя правила сортировки с учетом языка и региональных параметров, и текущий язык и региональные параметры.CurrentCultureIgnoreCase: Сравнивайте строки, используя правила сортировки с учетом языка и региональных параметров, текущий язык и региональные параметры, игнорируя регистр сравниваемых строк.InvariantCulture: Сравнивайте строки, используя правила сортировки с учетом языка и региональных параметров и инвариантный язык и региональные параметры.InvariantCultureIgnoreCase: Сравнивайте строки, используя правила сортировки с учетом языка и региональных параметров, инвариантный язык и региональные параметры и игнорируя регистр сравниваемых строк.Ordinal: Сравнивайте строки, используя порядковые (двоичные) правила сортировки.OrdinalIgnoreCase: Сравнивайте строки, используя правила порядковой (двоичной) сортировки и игнорируя регистр сравниваемых строк.
Отсюда переход к обычным аналогам:
Console.WriteLine(String.Join(", ", letters.Order(StringComparer.Ordinal)));
Console.WriteLine(String.Join(", ", letters.Order(StringComparer.OrdinalIgnoreCase)));
Результатом будет ожидаемый результат:
X, Z, y
X, y, Z
Спасибо, Гуру Строн, ваш ответ тоже полезен. :-)
Попробуйте это: dotnetfiddle.net/SQ0p6q