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.
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
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?
Your best bet is to use
yieldand an extension method:Granted, the call to
OrderByis going to cause a full iteration of therangessequence, but there’s no avoiding that. Once you have it ordered, you can prevent having to materialize your results before returning them; you simplyyieldthe results if the conditions dictate.If you know that the sequence is ordered, however, then you don’t have to call
OrderByat all, and you canyielditems as you traverse the list and break on different collapsedRangeinstances.Ultimately, if the sequence is unordered, then you have two options:
OrderByis deferred as well, but will have to use one full iteration to order the sequence), usingyieldto return the item when you have one to process