Проблема сортировки строк в С#

У меня есть список как

    List<string> items = new List<string>();
    items.Add("-");
    items.Add(".");
    items.Add("a-");
    items.Add("a.");
    items.Add("a-a");
    items.Add("a.a");

    items.Sort();

    string output = string.Empty;
    foreach (string s in items)
    {
        output += s + Environment.NewLine;
    }

MessageBox.Show(output);

Выход возвращается как

-
.
a-
a.
a.a
a-a

где, поскольку я ожидаю результатов как

-
.
a-
a.
a-a
a.a

Любая идея, почему "a-a" не предшествует "a.a", где "a-" предшествует "a".

Ответ 1

Если вы хотите, чтобы ваш сортировка строк основывалась на фактическом значении байта, в отличие от правил, определенных текущей культурой, вы можете сортировать по ординалу:

items.Sort(StringComparer.Ordinal);

Это позволит сделать результаты согласованными во всех культурах (но это приведет к неинтуитивным сортировкам "14", которые предшествуют "9", что может быть или не быть тем, что вы ищете).

Ответ 2

Я подозреваю, что в последнем случае "-" обрабатывается по-другому из-за специфических для культуры настроек (возможно, как "тире", а не "минус" в первых строках). MSDN предупреждает об этом:

Сравнение использует текущую культуру для получения специфических для культуры информации, такой как правила обсадной колонны и алфавитный порядок индивидуальные символы. Например, культура может указать, что некоторые комбинации символов рассматриваются как один символ, или символы верхнего и нижнего регистра сравниваются определенным образом, или что порядок сортировки персонажа зависит от символов которые предшествуют или следуют за ним.

Также см. эту страницу MSDN:

В .NET Framework используются три разных способа сортировки: сортировка слов, сортировка строк и сортировка по порядку. Сортировка Word выполняет чувствительную к культуре сравнение строк. Некоторые неалфанумерные символы могут иметь специальные веса, назначенные им; например, дефис ( "-" ) может имеют очень небольшой вес, назначенный ему, чтобы "курятник" и "кооператив", появляются рядом друг с другом в отсортированном списке. Строковая сортировка аналогична словосочетание, за исключением того, что особых случаев нет; поэтому все nonalphanumeric символы поступают перед всеми буквенно-цифровыми символами. Ordinal sort сравнивает строки, основанные на значениях Unicode каждого элемент строки.

Итак, дефис получает специальное лечение в режиме сортировки по умолчанию, чтобы сделать слово более "естественным".

Вы можете получить "обычный" порядковый номер, если вы его включите:

     Console.WriteLine(string.Compare("a.", "a-"));                  //1
     Console.WriteLine(string.Compare("a.a", "a-a"));                //-1

     Console.WriteLine(string.Compare("a.", "a-", StringComparison.Ordinal));    //1
     Console.WriteLine(string.Compare("a.a", "a-a", StringComparison.Ordinal));  //1

Чтобы отсортировать исходную коллекцию, используя использование сравнения по порядку:

     items.Sort(StringComparer.Ordinal);

Ответ 3

Метод Sort класса List<> полагается на сопоставитель по умолчанию string.NET Framework, который на самом деле является экземпляром текущего CultureInfo для Thread.

CultureInfo указывает алфавитный порядок символов, и кажется, что по умолчанию используется порядок, отличный от того, что вы ожидаете.

При сортировке вы можете указать конкретный CultureInfo, который, как вы знаете, будет соответствовать вашим требованиям сортировки, образец (немецкая культура):

var sortCulture = new CultureInfo("de-DE");
items.Sort(sortCulture);

Более подробную информацию можно найти здесь:
http://msdn.microsoft.com/en-us/library/b0zbh7b6.aspx
http://msdn.microsoft.com/de-de/library/system.stringcomparer.aspx