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 排序依据问题(按自定义规则对字符串进行排序)

发生的情况是我的记录按字母顺序排序,是否有我可以使用的 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 个级别。有人有建议吗?