使用lambda表达式将列表拆分为多个列表

时间:2012-11-10 23:30:51

标签: c# linq lambda

class order {
    Guid employeeId;
    DateTime time;
}

我需要根据时间范围将订单列表过滤到4个列表中。 0-9AM至第1列表,上午9点至下午2点至下午2点至下午6点至第3点和下午6点至12点至第4列表。

我很好奇是否可以通过有效的方式使用lambda表达式实现这一点?否则什么是拆分列表的最佳方法?

5 个答案:

答案 0 :(得分:3)

这应该有效:

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);
// ...

答案 1 :(得分:2)

最可读的方法是使用命名函数进行分组并将其作为委托传递给GroupBy()

var orderGroups = orders.GroupBy(GetOrderGroup)

private int GetOrderGroup(order o)
{
    //implement your groups
}

答案 2 :(得分:1)

这应该可以解决问题:

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);

答案 3 :(得分:1)

我现在在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策略(带有排序的开销)。

我担心的是大型设备会对性能产生不利影响。例如,四个。所有评估将对所有对象执行四次比较,尽管这些组是互斥的。

我不知道你有多少数据,但为了你的缘故,我希望它有很多订单:)。无论如何,我可能会像我推荐的那样尝试在一次迭代中进行分组和比较。如果您不喜欢这个解决方案,我建议您自己迭代列表并构建您的集合而不需要linq到对象。

只是我的两分钱。

答案 4 :(得分:1)

使用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);