Как правильно отсортировать столбец с строковым номером в DataTable

Я пытаюсь отсортировать столбец с номерами строк, например, N1, N10, N100, N2, и я ожидаю результатов N1, N2, N10, N100, но сортировка не работает, я получаю те же значения N1, N10, N100, N2 в том же порядке.

Я написал следующий код.

static class ExtensionMethod
{
    public static DataTable SortAlphaNumeric(this DataTable datatable, string columnName)
    {
        return datatable.AsEnumerable()
                  .OrderBy(r => r.Field<String>(columnName), new CustomComparer())
                  .CopyToDataTable();
    }
}

public class CustomComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        var numberX = Regex.Match(x, @"\d+").Value;
        var numberY = Regex.Match(y, @"\d+").Value;

        var alphaX = Regex.Match(x, @"[^a-z]").Value;
        var alphaY = Regex.Match(y, @"[^a-z]").Value;

        if (alphaX.CompareTo(alphaY) == 0)
            return numberX.CompareTo(numberY);
        else if (alphaX.CompareTo(alphaY) < 0)
            return -1;
        return 1;            
    }
}

// Code example
class TestExample
{
    public void Test()
    {
        var dt = new DataTable();
        dt.Columns.Add("AlphaNumeric", Type.GetType("System.String"));
        var row = dt.NewRow();
        row["AlphaNumeric"] = "N1";
        dt.Rows.Add(row);
        row = dt.NewRow();
        row["AlphaNumeric"] = "N10";
        dt.Rows.Add(row);
        row = dt.NewRow();
        row["AlphaNumeric"] = "N100";
        dt.Rows.Add(row);
        row = dt.NewRow();
        row["AlphaNumeric"] = "N2";
        dt.Rows.Add(row);

        var orderedDt = dt.SortAlphaNumeric("AlphaNumeric");
    }
}

3 ответа

Решение

Изменение в вашем Comparer:

var numberX = int.Parse(Regex.Match(x, @"\d+").Value);
var numberY = int.Parse(Regex.Match(y, @"\d+").Value);

Я бы использовал (?<alpha>[A-Za-z])(?<number>\d+) как регулярное выражение и сравнить alpha (сравнение строк), а затем, если он равен, int.Parse number и сравнить это (целочисленное сравнение).

Это дает только два выполнения регулярных выражений вместо четырех (вероятно, компиляция регулярного выражения и помещение его в статическое поле также сделает его быстрее), и 2 будет меньше чем 10 если вы сравните реальные цифры. Если вы не анализируете числа, вы можете пропустить все регулярные выражения и просто сделать одно сравнение строк.

Если числовой формат является детерминированным (всегда строка + целое число), вы можете просто сохранить их в двух отдельных полях (в идеале, обратно в БД. Составные ключи - вещь в конце концов). Тогда это "сортировка по строке сначала, номер 2".

Если это не так, вещи будут жесткими. То, что вы хотите, это довольно необычная сортировка, которую Windows делает с файлами. Помимо пользовательских решений регулярных выражений (но, опять же, если это тот детерминист, который вы, вероятно, можете использовать 2 или более полей), был бы StrCmpLogicalW. Но и тот, и другой неуправляемый, и его поведение различается между Windows (это "каноническая" сортировка для Windows, на которой он работает, но эта сортировка варьировалась между версиями Windows).

Другие вопросы по тегам