【问题标题】:Linq sort with Null values使用 Null 值进行 Linq 排序
【发布时间】:2017-02-22 03:12:31
【问题描述】:

我有一个具有一个字符串属性的类,它有时可以为空,有时可以是整数,也可以是字符串。

我想使用 LINQ 在此属性的基础上进行排序,整数值按升序排列,所有 nono 整数值下一个,最后为空值

如何制作处理场景的 LINQ 表达式

例子

"1" ,NULL , "34", "6" ,"67",NULL ,"r45","j34" ,"s"  to be sorted as 

"1" "6" "34"  "67" "j34" "r45" "s" NULL NULL

我试过这样的东西,但不是很完美答案是

var licenseitems_master =  my master list 
var firstPart = licenseitems_master.Where(x => !String.IsNullOrEmpty(x.Page) && x.Page.All(char.IsDigit)).OrderBy(x => Convert.ToInt32(x.Page));
var secondPart = licenseitems_master.Where(x => !String.IsNullOrEmpty(x.Page) && !x.Page.All(char.IsDigit)).OrderBy(x => x.Page);
var thirdPart = licenseitems_master.Where(x => String.IsNullOrEmpty(x.Page)).ToList();
var sorted_items = firstPart.Union(secondPart).Union(thirdPart).ToList();

我们可以把它做成一个单一的 LINQ 表达式吗?

【问题讨论】:

  • 您应该使用自己的比较器。好的解释在这里stackoverflow.com/questions/24841170/linq-custom-sort
  • 你必须在你的类中重写 EqualsGetHashCode 方法。然后就像var sorted_items = licenseitems_master.OrderBy(x => x.Page).ToList(); 一样简单
  • 为什么一个变量有不同的数据类型?
  • 它是客户的要求,页面有时可以是字符串,例如 rj45 或只是一个数字,它不是必填字段
  • @PawełHemperek:嗯,不是真的。只需从使用 Union 更改为 Concat 即可避免使用 any 相等比较的代码。不过,自定义比较器是执行排序的正确方法。

标签: c# linq linq-to-sql


【解决方案1】:

在这种情况下,典型的方法是首先按某个优先级表达式排序,然后按其他表达式排序(仅对相同优先级生效)。在您的场景中,它可能是这样的:

var sorted_items =
    (from x in licenseitems_master
     let pageOrder = string.IsNullOrEmpty(x.Page) ? 2 : x.Page.All(char.IsDigit) ? 0 : 1
     orderby pageOrder, pageOrder == 0 ? Convert.ToInt32(x.Page) : 0, x.Page
     select x).ToList();

【讨论】:

    【解决方案2】:

    你也可以去做类似的事情。

    首先:TryParse 转为 int,并按该值排序(如果无法解析,则将该值替换为 Int32.MaxValue,这会将这些值放在末尾)。

    第二:把null放在最后。

    第三:按“字符串”值排序结果

    int outValue;
    var result = input
                    .OrderBy(m => Int32.TryParse(m, out outValue)
                        ? outValue
                        : Int32.MaxValue)
                    .ThenBy(m => m == null)
                    .ThenBy(m => m)
                    .ToList();
    

    【讨论】:

      【解决方案3】:

      这是使用 Linq 的一种方法

      • 按 null / not nul 升序排列
      • 然后按数字升序排列
      • 然后按升序排序

      List<string>测试

      var input = new List<string>() { "1", null, "34", "6", "67", null, "r45", "j34", "s" };
      List<string> result = input.OrderBy(x => x == null)
            .ThenBy(x => x != null && x.All(y => char.IsDigit(y)) ? int.Parse(x) : int.MaxValue)
            .ThenBy(x => x).ToList();
      

      我也更喜欢这种情况下的自定义比较器(更容易阅读/维护),但问题是关于 Linq 方法

      【讨论】:

      • 这正是我正在寻找的。我试过了,但是顺序并没有真正升序,我得到的结果是 1 , 34, 6, 67, j34,r45,null,null 。但是应该是 1,6,34,67,j34,r45,null,null
      • @JibinMathew 修复了这个问题
      【解决方案4】:

      也许你可以使用这种比较器:

      public class MyComparer : IComparer<string>
      {
          public int Compare(string x, string y)
          {
              if (x == null && y == null) return 0;
              if (x == null) return 1;
              if (y == null) return -1;
      
              if (x.All(char.IsDigit) && y.All(char.IsDigit))
              {
                  var n1 = Convert.ToInt32(x);
                  var n2 = Convert.ToInt32(y);
                  return n1 - n2;
              }
              return x.CompareTo(y);
          }
      }
      

      然后像这样使用它:

      var myComparer = new MyComparer();
      var sorted_items = "my master list".OrderBy(x => x.Page, myComparer).ToList();
      

      【讨论】:

        猜你喜欢
        • 2016-08-04
        • 1970-01-01
        • 2018-07-26
        • 2021-06-30
        • 2012-01-28
        • 2010-12-31
        • 1970-01-01
        • 1970-01-01
        • 2011-10-21
        相关资源
        最近更新 更多