Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine Time Ranges

Tags:

c#

datetime

union

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

like image 713
thecaptain0220 Avatar asked Oct 29 '12 21:10

thecaptain0220


People also ask

How do you combine intervals?

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.

How do you combine ranges in python?

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.

What are overlapping intervals?

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.

How do you sort an interval array?

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.


2 Answers

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

enter image description here

like image 98
Tim Schmelter Avatar answered Oct 20 '22 21:10

Tim Schmelter


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

like image 40
Johan Larsson Avatar answered Oct 20 '22 19:10

Johan Larsson