Пользовательская Сортировка C# Linq

у меня есть запрос в linqtosql, который возвращает LabelNumber:

var q = from list in db.Lists
        select list.LabelNumber;

становится IEnumerable<string> С такими элементами:

{"1","2","2.A","2.B","3","3.A","3.B"}

Я в основном хочу упорядочить элементы, как они появляются выше, но я не могу использовать OrderBy(x=>x.LabelNumber), потому что "10" будет помещен после "1" и перед "2".

Я предполагаю, что мне нужно написать пользовательскую функцию компаратора, но как это сделать с linq?

Edit: я думаю, что все ответы ниже будут работать, но одно предостережение должно быть добавлено ко всем ответам.

если вы используете Linq2SQL, вы не можете использовать индексы массива в запросе. Чтобы преодолеть это, у вас должно быть два запроса. Тот, который читает с SQL. Второй делает заказ:

var q = from list in db.Lists
            select list.LabelNumber;

var q2 = q.AsEnumerable()
          .OrderBy(x => int.Parse(x.LabelNumber.Split('.')[0]))
          .ThenBy(x => x.Number
                        .Contains(".") ? 
                              x.LabelNumber.Split('.')[1].ToString() 
                              : 
                              string.Empty);

4 ответов


вам, вероятно, не нужно писать пользовательский компаратор. Если все ваши ярлыки в форме number.letter, вы можете использовать это.

var query = from list in db.Lists
            let split = list.LabelNumber.Split('.')
            let order = split.Length == 1
                ? new { a = int.Parse(split[0]), b = String.Empty }
                : new { a = int.Parse(split[0]), b = split[1] }
            orderby order.a, order.b
            select list.LabelNumber;

Если вам нужно больше контроля, вы всегда можете преобразовать sortby поля (a и b) для соответствующих типов, а не для ints и строк.


если это LINQ-to-SQL, это фактически не будет работать, так как некоторые методы, используемые здесь, не поддерживаются. Вот разделяемый вариант. Она не уступит самой красивой. запрос, но он будет работать.

var query = from list in db.Lists
            let dot = list.LabelNumber.IndexOf('.')
            let name = list.LabelNumber
            let order = dot == -1
                ? new { a = Convert.ToInt32(name.Substring(0, dot)), b = String.Empty }
                : new { a = Convert.ToInt32(name.Substring(0, dot)), b = name.Substring(dot+1) }
            orderby order.a, order.b
            select list.LabelNumber;

OrderBy(x=>x.LabelNumber, new AlphanumComparator())

здесь AlphanumComparator - отличное Алфавитный алгоритм естественной сортировки Дэвид Koelle. Нет необходимости изобретать колесо.

если вы собираетесь использовать версию c#, измените ее на:

AlphanumComparator : IComparer<string>

и

public int Compare(string x, string y)

Если вы уверены, что q хорошо отформатирован и секвенирован:

var result = q.OrderBy(x => int.Parse(x.Split('.')[0]));

вот мой вклад.. используя Regular Expression и LAMBDA expression

List<String> Lst = new List<string> { "1", "2", "2.A","10.A", "2.C", "3", "3.A", "3.B","2.B","11.D" };
Lst = Lst.Select(X => new
        {
            Number = int.Parse( Regex.Match(X, @"([0-9]*).?([a-zA-Z]*)").Groups[1].Value),
            Strings=Regex.Match(X, @"([0-9]*).?([a-zA-Z]*)").Groups[2].Value,
            OriginalString = X
        }).OrderBy(X => X.Number).ThenBy(X=>X.Strings)
        .Select(X => X.OriginalString).ToList();

выход:

"1"
"2"
"2.A"
"2.B"
"2.C"
"3"
"3.A"
"3.B"
"10.A"
"11.D"