Пользовательская Сортировка 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"