【问题标题】:Linq OrderBy Sub ListLinq OrderBy 子列表
【发布时间】:2014-12-29 18:33:31
【问题描述】:

我正在尝试执行一个相当简单的订单,但似乎在努力解决如何去做。以我有这两个类为例。

public class Method
{
    public int Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set; }

    public List<Slot> Slots { get; set; }
}

public class Slot
{
    public DateTime ExpectedDeliveryDate { get; set; }
}

使用下面的代码,我想按最便宜的选项订购,然后按最快的交货日期订购。

var methods = new List<Method>();

methods.Add(new Method { Id = 1, Name = "Standard", Price = 0M, Slots = new List<Slot> { new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(5).Date } } });
methods.Add(new Method { Id = 2, Name = "Super Fast Next Day", Price = 0M, Slots = new List<Slot> { new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(1).Date } } });

var b = methods.OrderBy(x => x.Price)
    .ThenBy(y => y.Slots.OrderBy(t => t.ExpectedDeliveryDate.Date)
        .ThenBy(t => t.ExpectedDeliveryDate.TimeOfDay))
            .ToList();

我在这里遇到的麻烦是我收到一个运行时错误,指出“至少一个对象必须实现 IComparable”。

虽然我可以通过实现 IComparable 接口来解决这个问题,但我想知道是否可以这样做。我想好像我有这段代码(见下文)它工作正常。

var slots = new List<Slot>();

slots.Add(new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(5).Date });
slots.Add(new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(1).Date });
slots.Add(new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(3).Date });
slots.Add(new Slot { ExpectedDeliveryDate = DateTime.Now.Date });

var d = slots.OrderBy(x => x.ExpectedDeliveryDate);

干杯,DS。

对于上面示例中的变量命名(例如 xyz)表示歉意 :) 可以复制和粘贴代码以获得操作乐趣。

编辑 - 更新以简化代码示例。 - 排序成功后的预期结果

Input
  ID     Name            Price    Slot
  1      Standard        0        DateTime.Now.AddDays(5).Date
  2      Super Fast      0        DateTime.Now.Date

Output
  2      Super Fast      0        DateTime.Now.Date  
  1      Standard        0        DateTime.Now.AddDays(5).Date

所以我的超快速选项应该是首选,因为它是最便宜的,当然还有最快的交货日期。

【问题讨论】:

  • 不清楚您希望它意味着按其插槽订购一组交付方式。你能给出样本数据和预期结果吗?为什么要按年、月、日(这并不意味着我认为您认为的意思)而不是仅按 ExpectedDeliveryDate 本身订购?
  • @DrSchizo 您尚未澄清的部分是您的每个方法都可以有多个插槽,但是您的预期结果示例仅显示每个方法一个插槽。当一个方法有多个插槽时,预期的行为是什么?什么时候有零槽?为了让这个问题有意义,您需要决定在这种情况下应该发生什么。
  • 约翰已经回答了这类问题:stackoverflow.com/a/14141926/213550
  • 如果它有多个插槽,那么它应该选择日期最早的项目到今天。我开始认为唯一的选择是实现 IComparable .. @Admin 为编辑欢呼,不知道如何在现场格式化表格:)
  • @DrSchizo 如果有一些零槽怎么办?

标签: c# linq sorting


【解决方案1】:

您可以使用Enumerable.Min() 来选择日期最早的插槽,如下所示:

        var query = deliveryMethods
            .OrderBy(x => x.Slots.Min(s => s.ExpectedDeliveryDate).Year)
            .ThenBy(x => x.Slots.Min(s => s.ExpectedDeliveryDate).Month)
            .ThenBy(x => x.Slots.Min(s => s.ExpectedDeliveryDate).Date)
            .ToList();

或者,只是

        var query = deliveryMethods
            .OrderBy(x => x.Slots.Min(s => s.ExpectedDeliveryDate.Date))
            .ToList();

请注意Min() 在输入序列为空且被最小化的类型是值类型时会抛出异常。如果你想避免异常,你可以这样做:

        var query2 = deliveryMethods
            .OrderBy(x => x.Slots.Min(s => (DateTime?)(s.ExpectedDeliveryDate.Date)))
            .ToList();

通过将DateTime 转换为可空值,Min() 将为空序列返回空值,而具有空槽列表的Method 对象将被排序到开头。

【讨论】:

  • 我一定是弄丢了我的弹珠,我昨晚出于某种奇怪的原因试过了,但我得到了一个 IComparable 异常。但是,我想这里的关键是使用“Min” :)
【解决方案2】:

我想解释一下为什么您在原始帖子中发布的尝试不起作用:

var xyz = deliveryMethods
        .OrderBy(x => x.Slots.OrderBy(y => y.ExpectedDeliveryDate.Year))
        .ThenBy(x => x.Slots.OrderBy(y => y.ExpectedDeliveryDate.Month))
        .ThenBy(x => x.Slots.OrderBy(y => y.ExpectedDeliveryDate.Date))
        .ToList();

这是因为您将OrderBys 嵌套在OrderBys 中。

x.Slots.OrderBy(...) 产生一个IEnumerable&lt;Slot&gt;,所以您基本上是在告诉它“将这些IEnumerable&lt;Slot&gt;s 相互比较以确定交付方式的顺序”。但是 Linq 不知道如何将 IEnumerable&lt;Slot&gt; 与另一个进行比较并决定哪个在另一个之前(IEnumerable&lt;Slot&gt; 没有实现 IComparable&lt;T&gt;),所以你得到了一个错误。

正如另一位用户指出的那样,答案是给它一些可以比较的东西。正如您后来澄清的那样,这将是每种交付方式的最早时段:

var xyz = deliveryMethods
        .OrderBy(x => x.Slots.Min(y => y.ExpectedDeliveryDate))
        .ToList();

这将在每个传递方法至少有一个槽的假设下工作,但如果其中任何一个槽的槽为零(或者如果Slots 为空),则会引发运行时异常。我已经问过你两次在这种情况下应该怎么做,我鼓励你澄清一下。

一种可能的解决方案是仅包含具有插槽的交付方法:

var xyz = deliveryMethods
        .Where(x => x.Slots != null && x.Slots.Any())
        .OrderBy(x => x.Slots.Min(y => y.ExpectedDeliveryDate))
        .ToList();

【讨论】:

  • 对orderby的嵌套很好的解释。正如您所指出的,插槽不包含任何项目或为空的副作用是一个问题,但有一个解决方案。
  • @DrSchizo 我为无槽/空槽问题提供了一种可能的解决方案。
猜你喜欢
  • 1970-01-01
  • 2017-08-15
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2021-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多