LINQ Group通过连续时间 [英] LINQ GroupBy continuous time

查看:52
本文介绍了LINQ Group通过连续时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个简单的结构,如下所示:

Assuming I have a simple structure that looks like this:

public class Range
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }

    public Range(DateTime start, DateTime end)
    {
        this.Start = start;
        this.End = end;
    }
}

然后我像这样创建一个集合:

And I create an collection like so:

var dr1 = new Range(new DateTime(2011, 11, 1, 12, 0, 0), 
    new DateTime(2011, 11, 1, 13, 0, 0));
var dr2 = new Range(new DateTime(2011, 11, 1, 13, 0, 0), 
    new DateTime(2011, 11, 1, 14, 0, 0));
var dr3 = new Range(new DateTime(2011, 11, 1, 14, 0, 0), 
    new DateTime(2011, 11, 1, 15, 0, 0));
var dr4 = new Range(new DateTime(2011, 11, 1, 16, 0, 0), 
    new DateTime(2011, 11, 1, 17, 0, 0));

var ranges = new List<Range>() { dr1, dr2, dr3, dr4 };

我要对连续的范围进行分组-即,如果前一个范围的结束"值与下一个范围的开始"值相同,则它们是连续的.

What I want to do is group the ranges where they are continuous - i.e. they are continuous if the End value of the previous Range is the same as the Start of the next.

我们可以假设Range值中没有冲突/重复或重叠.

We can assume that there are no collisions/duplicates or overlaps in the Range values.

在发布的示例中,我将分为两组:

In the example posted, I would end up with two groups:

2011-11-1 12:00:00 - 2011-11-1 15:00:00

2011-11-1 16:00:00 - 2011-11-1 17:00:00

为此很容易找到一个迭代解决方案.但是,有没有什么我可以使用LINQ魔术贴来实现的呢?

It's fairly easy to come up with an iterative solution for this. But is there some LINQ magic I can use to get this in a pretty one-liner?

推荐答案

您最好的选择是使用 yield 和扩展方法:

Your best bet is to use yield and an extension method:

static IEnumerable<Range> GroupContinuous(this IEnumerable<Range> ranges)
{
    // Validate parameters.

    // Can order by start date, no overlaps, no collisions
    ranges = ranges.OrderBy(r => r.Start);

    // Get the enumerator.
    using (IEnumerator<Range> enumerator = ranges.GetEnumerator();
    {
        // Move to the first item, if nothing, break.
        if (!enumerator.MoveNext()) yield break;

        // Set the previous range.
        Range previous = enumerator.Current;

        // Cycle while there are more items.
        while (enumerator.MoveNext())
        {
            // Get the current item.
            Range current = enumerator.Current;

            // If the start date is equal to the end date
            // then merge with the previous and continue.
            if (current.Start == previous.End)
            {
                // Merge.
                previous = new Range(previous.Start, current.End);

                // Continue.
                continue;
            }

            // Yield the previous item.
            yield return previous;

            // The previous item is the current item.
            previous = current;
        }

        // Yield the previous item.
        yield return previous;
    }
}

已授予,对 OrderBy 的调用导致ranges序列的完整迭代,但是无法避免.订购完成后,您可以避免在返回结果之前将其具体化.只要条件允许,您只需yield结果.

Granted, the call to OrderBy is going to cause a full iteration of the ranges sequence, but there's no avoiding that. Once you have it ordered, you can prevent having to materialize your results before returning them; you simply yield the results if the conditions dictate.

但是,如果您知道序列是有序的,则根本不必调用OrderBy,并且在遍历列表并在不同的折叠的Range实例上断开时可以yield个项目.

If you know that the sequence is ordered, however, then you don't have to call OrderBy at all, and you can yield items as you traverse the list and break on different collapsed Range instances.

最终,如果序列是无序的,那么您有两个选择:

Ultimately, if the sequence is unordered, then you have two options:

  • 对列表进行排序,然后进行处理(请记住,OrderBy也被推迟,但是必须使用一个完整的迭代来对序列进行排序),如果需要处理,则使用yield返回该项目
  • 立即处理整个序列,然后作为完整的物化序列返回
  • Order the list and then process (remember, OrderBy is deferred as well, but will have to use one full iteration to order the sequence), using yield to return the item when you have one to process
  • Process the entire sequence at once and return as an entire materialized sequence

这篇关于LINQ Group通过连续时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆