我正在努力执行一个相当简单的订单,但似乎正在努力如何去做。举个例子,我有这两个类。
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
所以我的超快选项应该是最好的,因为它是最便宜的,当然有最快的交货日期。
答案 0 :(得分:6)
您可以使用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()
将为空序列返回null,并且具有空槽列表的Method
对象将被排序到开头。
答案 1 :(得分:1)
我想解释为什么您在原始帖子中发布的尝试无效:
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();
这是因为你在OrderBy
内嵌套OrderBy
s。
x.Slots.OrderBy(...)
生成IEnumerable<Slot>
,因此您基本上是在告诉它&#34;将这些IEnumerable<Slot>
相互比较以确定交付方式的顺序&#34;。但Linq不知道如何将IEnumerable<Slot>
与另一个进行比较并确定哪一个来自另一个(IEnumerable<Slot>
未实现IComparable<T>
),因此您收到错误。
正如另一位用户所指出的那样,答案是给它一些可以进行比较的东西。正如您后来澄清的那样,这将是每种交付方式的最早时段:
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();