I have an array with several time ranges inside:
[Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00,
Tue, 24 May 2011 16:30:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00,
Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 09:00:00 CEST +02:00,
Tue, 24 May 2011 15:30:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00]
I want to get the same array with the overlapping time ranges combined, so the output for this case will be:
[Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00,
Tue, 24 May 2011 15:30:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00]
So it creates a new time range when to time ranges overlap, and so on. If they don´t overlap the will be keep separated. Another example:
Input:
[Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00,
Tue, 24 May 2011 16:00:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00]
Output (will be the same because they don´t overlap):
[Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00,
Tue, 24 May 2011 16:00:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00]
I was thinking in some recursive approach, but I need some guidance here...
The solution, offered by @wayne-conrad is a very good one. I implemented it for a problem, I stumbled upon. Then I implemented an iterative version and benchmarked the two. It appears, the iterative version is quicker. Note: I use
ActiveSupport
forRange#overlaps?
and the time helpers, but it is trivial to implement a pure-Ruby version.The facets gem has
Range.combine
method that may be of use: http://rdoc.info/github/rubyworks/facets/master/Range#combine-instance_methodDont you just want to find the smallest first value and the largest last value from the set of arrays?
Some kind of algorithm that might help:
Given a function that returns truthy if two ranges overlap:
(this function courtesy of sepp2k and steenslag)
and a function that merges two overlapping ranges:
then this function, given an array of ranges, returns a new array with any overlapping ranges merged:
The Marked answer works well except for few use cases. One of such use case is
The condition in
ranges_overlap
does not handle this use case. So I wrote thisThis is handling all the edge cases for me so far.