LINQ 排序依据问题(按自定义规则对字符串进行排序)
本文关键字:排序 字符串 规则 问题 LINQ 自定义 | 更新日期: 2023-09-27 18:35:11
我有一个 linq 查询,它没有按照我想要的方式排序。
查询:
return (from obj in context.table_orders
orderby obj.order_no
select obj.order_no.ToString() + '-' + obj.order_description).ToList<string>();
发生的情况是我的记录按字母顺序排序,是否有我可以使用的 Linq 关键字来正确排序我的记录(因此订单 30 在订单 100 之前)?
我希望结果是一个字符串列表,因为这用于填充组合框。
数据库中的一些"order_no"也像"2.10"和"9.1.1"。
发生的情况是我的记录按字母顺序排序,是否有我可以使用的 Linq 关键字,以便我的记录是 正确订购(因此订单 #30 在订单 #100 之前)?
如果我每次有人问这个问题时都能得到一分钱,我就会很富有。
是的,有 - 简单的答案:订购数字而不是字符串。
所以订单 #30 在订单 #100 之前)
但是 #30 在 #100 之后,原因很简单,它们是按字母顺序排序的,因为它们是字符串。
解析字符串,将数字转换为 - well-一个数字,然后按它排序。
任何认为order_no应该是没有固定长度的字符串(如 00030)的人都应该 - 好吧 - ;)接受有关数据库建模的基础教育。我真的很喜欢发票编号等东西是字符串(它们不是数字),但将它们保持在 (a) 可反抗的模式和 (b) 校验和(以便轻松捕获数据输入错误)应该是基础知识;)
这是初级人员定义数据库和数据模型而不考虑后果时遇到的问题。
你会遇到一些痛苦 - 解析字符串,按解析结果排序。
如果obj.order_no
是字符串,则将其转换为数字进行排序
orderby Int32.Parse(obj.order_no)
或
orderby Decimal.Parse(obj.order_no)
原因 仅当字符串表示有效数字时,这才有效。
如果order_no
不是有效的数字(例如 "17.7-8A"
) 然后编写一个函数,将其格式化为包含右对齐的数字,例如"00017.007-0008A"
并使用此函数进行排序
orderby FormatOrderNo(obj.order_no)
更新
由于您正在使用 EF,因此无法在查询的 EF 部分中调用此函数。将 EF 结果转换为IEnumerable<T>
并使用 LINQ To 对象执行排序
return (from obj in context.table_orders select ...)
.AsEnumerable()
.OrderBy(obj => FormatOrderNo(obj.order_no))
.ToList();
根据你所说的 - 数字不是真正的数字,而是自定义序列标识符(即你甚至不知道你得到的深度水平),我建议实现一个自定义比较器。
如果你这样做,你可以定义你想要什么 - 那就是我相信这些东西:
- 在
.
上拆分字符串
比较序列, - 包括数组。较短序列的长度 如果有一个较短的序列
- ,并且现在有一个平局,则在较长的序列之前选择较短的(即
2.1
2.1.1
之前
) - 如果两个序列的长度相同,在比较结束时,您应该知道哪个序列"更大"
- 解决。
如果您需要有关IComparer
实现的灵感,请在以下示例中
:http://zootfroot.blogspot.co.uk/2009/09/natural-sort-compare-with-linq-orderby.html
可能的话,我会更改数据类型,或者如果适用,将其添加为另一个firld。如果这是不行的,您可以查看其他人在此问题中提到的解决方案,但要注意 - .ToList() 选项非常适合小表,如果你从它们中提取所有内容,但习惯它最终会给你带来一个痛苦的世界。从长远来看,您不想获得所有内容,要么使用 Where 或顶部标准。
其他解决方案很好,但对于我的口味来说很复杂,无法完成任务。
你可以直接通过LinqToSql拍摄sql http://msdn.microsoft.com/en-us/library/bb399403.aspx。
在sql中,您可以随意转换和排序。有些人认为这是一个好主意,有些人会告诉你它不好。您放弃了强大的类型并获得性能。你必须知道你为什么做出这种决定,恕我直言,这是最重要的事情。
由于没有人想出可转换为SQL的自定义orderby函数,因此我选择了IComparer函数,如下所示:
public class OrderComparer<T> : IComparer<string>
{
#region IComparer<string> Members
public int Compare(string x, string y)
{
return GetOrderableValue(x.Split('-').First()).CompareTo(GetOrderableValue(y.Split('-').First()));
}
#endregion
private int GetOrderableValue(string value)
{
string[] splitValue = value.Split('.');
int orderableValue = 0;
if (splitValue.Length.Equals(1))
orderableValue = int.Parse(splitValue[0]) * 1000;
else if (splitValue.Length.Equals(2))
orderableValue = int.Parse(splitValue[0]) * 1000 + int.Parse(splitValue[1]) * 100;
else if (splitValue.Length.Equals(3))
orderableValue = int.Parse(splitValue[0]) * 1000 + int.Parse(splitValue[1]) * 100 + int.Parse(splitValue[2]) * 10;
else
orderableValue = int.Parse(splitValue[0]) * 1000 + int.Parse(splitValue[1]) * 100 + int.Parse(splitValue[2]) * 10 + int.Parse(splitValue[3]);
return orderableValue;
}
}
这些值最多有 4 个级别。有人有建议吗?