class order {
Guid employeeId;
DateTime time;
}
我需要根据时间范围将订单列表过滤为 4 个列表。0-9AM 到第 1 个列表,9AM-2PM 到第 2 个列表,2-6PM 到第 3 个列表和 6-12PM 到第 4 个列表。
我很好奇这是否可以有效地使用 lambda 表达式来实现?否则拆分列表的最佳方法是什么?
这应该有效:
var orders = list.OrderBy(o => o.time);
var first = orders.TakeWhile(o => o.time.TimeOfDay.TotalHours <= 9);
var second = orders.SkipWhile(o => o.time.TimeOfDay.TotalHours <= 9)
.TakeWhile(o => o.time.TimeOfDay.TotalHours <= 14);
var third = orders.SkipWhile(o => o.time.TimeOfDay.TotalHours <= 14)
.TakeWhile(o => o.time.TimeOfDay.TotalHours <= 18);
var fourth = orders.SkipWhile(o => o.time.TimeOfDay.TotalHours <= 18);
这是另一种可能更有效、更灵活、更简洁的方法,它使用Enumerable.GroupBy
:
var groups = list.Select(o => new
{
Order = o,
DayPart = o.time.TimeOfDay.TotalHours <= 9 ? 1
: o.time.TimeOfDay.TotalHours > 9 && o.time.TimeOfDay.TotalHours <= 14 ? 2
: o.time.TimeOfDay.TotalHours > 14 && o.time.TimeOfDay.TotalHours <= 18 ? 3 : 4
})
.GroupBy(x => x.DayPart)
.OrderBy(g => g.Key);
var first = groups.ElementAt(0);
var second = groups.ElementAt(1);
// ...
最易读的方法是使用命名函数进行分组并将其作为委托传递给 GroupBy()
var orderGroups = orders.GroupBy(GetOrderGroup)
private int GetOrderGroup(order o)
{
//implement your groups
}
这应该可以解决问题:
var first = orders.Where(o => o.time.Hour >= 0 && o.time.Hour < 9);
var second = orders.Where(o => o.time.Hour >= 9 && o.time.Hour < 14);
var third = orders.Where(o => o.time.Hour >= 14 && o.time.Hour < 18);
var fourth = orders.Where(o => o.time.Hour >= 18 && o.time.Hour < 24);
我现在在 OSX 中,所以我无法测试解决方案,但我可能会在我的订单类中添加一个属性来计算组。我觉得你的订单会合理地关注这一点。所以,你可以有这样的东西:
class order {
Guid employeeId;
DateTime time;
public int Group { get { return /* check hours of day to group /} }
}
然后,它应该像orders.GroupBy(o => o.Group)
;
如果您觉得您的订单不应该知道这些组,您可以使用另一种方法,您认为定义组更重要。那你还是可以说orders.GroupBy(o => GetGroupNumber(o))
。
如果下次我在 Windows 中您仍然需要帮助,我会为您编写一个片段。
编辑:
我注意到这个问题的其他几个答案建议在您要创建的每个子列表的原始列表上执行 Where 或 Skip-Take 策略(带有排序的开销)。
我担心的是大型集会损害性能。例如,四个 .Where 评估将对所有对象执行四次比较,尽管这些组是互斥的。
我不知道你有多少数据,但为了你,我希望有很多订单:)。无论如何,我可能会尝试像我推荐的那样在一次迭代中进行分组和比较。如果您不喜欢该解决方案,我建议您自己遍历列表并在没有 linq 到对象的情况下构建您的集合。
只是我的两分钱。
使用该DateTime.TimeOfDay.TotalHours
属性很重要,它将返回由整数小时和小数小时表示的时间。
var endTimes = new List<int>() { 9, 14, 18, 24 };
var results = orders.GroupBy(o => endTimes.First(t => o.time.TimeOfDay.TotalHours < t))
.OrderBy(g => g.Key);