I am currently working on a C# program where I have the need to combine a bunch of time ranges. For each range I have the start and end time. I found an example where this was being done in Ruby but not for C#. I am basically looking for the time range union. I feel like there might be a way to do this using linq but I cant come up with it. Any ideas?
So for example
Start Time: 1:30 End Time: 2:00
Start Time: 1:45 End Time: 2:30
Start Time: 3:00 End Time: 5:00
Start Time: 4:00 End Time: 4:30
Start Time: 4:45 End Time: 5:30
This set of times would come back as
Start Time: 1:30 End Time: 2:30
Start Time: 3:00 End Time: 5:30
A simple approach is to start from the first interval and compare it with all other intervals for overlapping, if it overlaps with any other interval, then remove the other interval from the list and merge the other into the first interval. Repeat the same steps for the remaining intervals after the first.
Python doesn't have a built-in function to merge the result of two range() output. However, we can still be able to do it. There is a module named 'itertools' which has a chain() function to combine two range objects.
Let's take the following overlapping intervals example to explain the idea: If both ranges have at least one common point, then we say that they're overlapping. In other words, we say that two ranges and are overlapping if: On the other hand, non-overlapping ranges don't have any points in common.
Sort the intervals array according to startTime. Create an array to store the merged intervals. If the current and previous intervals does not overlap each other, append the current interval to the merged array. Else, merge both previous and current intervals and insert it into the merged array.
You could have a look at this project which supports TimeRanges
and intersection methods:
http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET
This looked fun so I started coding something.
public class TimeRanges
{
private List<TimeRange> _mergedTimeRanges = new List<TimeRange>();
public void Add(TimeRange timeRange)
{
if(!_mergedTimeRanges.Any(x=>x.IsOverLap(timeRange)))
{
_mergedTimeRanges.Add(timeRange);
return;
}
while (_mergedTimeRanges.Any(x => x.IsOverLap(timeRange) && x!=timeRange))
{
TimeRange toMergeRange = _mergedTimeRanges.First(x => x.IsOverLap(timeRange));
toMergeRange.Merge(timeRange);
timeRange = toMergeRange;
}
}
public IEnumerable<TimeRange> GetMergedRanges()
{
return _mergedTimeRanges;
}
}
public class TimeRange
{
public DateTime Start { get; private set; }
public DateTime End { get; private set; }
public TimeRange(DateTime start, DateTime end)
{
if (start >= end)
throw new ArgumentException("Invalid time range, end must be later than start");
Start = start;
End = end;
}
public void Merge(TimeRange timeRange)
{
if (!IsOverLap(timeRange))
throw new ArgumentException("Cannot merge timeranges that don't overlap", "timeRange");
if (End < timeRange.End)
End = timeRange.End;
if (timeRange.Start < Start)
Start = timeRange.Start;
}
public bool IsOverLap(TimeRange timeRange)
{
if (timeRange.End < Start)
return false;
if (timeRange.Start > End)
return false;
return true;
}
public bool Equals(TimeRange other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return other.Start.Equals(Start) && other.End.Equals(End);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof (TimeRange)) return false;
return Equals((TimeRange) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Start.GetHashCode()*397) ^ End.GetHashCode();
}
}
}
I have a couple of tests for it if anyone would be interested
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With