Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging a list of time-range tuples that have overlapping time-ranges

I have a list of tuples where each tuple is a (start-time, end-time). I am trying to merge all overlapping time ranges and return a list of distinct time ranges. For example

[(1, 5), (2, 4), (3, 6)] --->  [(1,6)] [(1, 3), (2, 4), (5, 8)] --->  [(1, 4), (5,8)] 

Here is how I implemented it.

# Algorithm # initialranges: [(a,b), (c,d), (e,f), ...] # First we sort each tuple then whole list. # This will ensure that a<b, c<d, e<f ... and a < c < e ...  # BUT the order of b, d, f ... is still random # Now we have only 3 possibilities #================================================ # b<c<d: a-------b           Ans: [(a,b),(c,d)] #                  c---d # c<=b<d: a-------b          Ans: [(a,d)] #               c---d # c<d<b: a-------b           Ans: [(a,b)] #         c---d #================================================ def mergeoverlapping(initialranges):     i = sorted(set([tuple(sorted(x)) for x in initialranges]))      # initialize final ranges to [(a,b)]     f = [i[0]]     for c, d in i[1:]:         a, b = f[-1]         if c<=b<d:             f[-1] = a, d         elif b<c<d:             f.append((c,d))         else:             # else case included for clarity. Since              # we already sorted the tuples and the list             # only remaining possibility is c<d<b             # in which case we can silently pass             pass     return f 

I am trying to figure out if

  1. Is the a an built-in function in some python module that can do this more efficiently? or
  2. Is there a more pythonic way of accomplishing the same goal?

Your help is appreciated. Thanks!

like image 721
Praveen Gollakota Avatar asked Apr 15 '11 16:04

Praveen Gollakota


People also ask

How do you merge overlapping ranges?

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 find overlapping time intervals?

1) Sort all intervals in increasing order of start time. This step takes O(nLogn) time. 2) In the sorted array, if start time of an interval is less than end of previous interval, then there is an overlap.


1 Answers

A few ways to make it more efficient, Pythonic:

  1. Eliminate the set() construction, since the algorithm should prune out duplicates during in the main loop.
  2. If you just need to iterate over the results, use yield to generate the values.
  3. Reduce construction of intermediate objects, for example: move the tuple() call to the point where the final values are produced, saving you from having to construct and throw away extra tuples, and reuse a list saved for storing the current time range for comparison.

Code:

def merge(times):     saved = list(times[0])     for st, en in sorted([sorted(t) for t in times]):         if st <= saved[1]:             saved[1] = max(saved[1], en)         else:             yield tuple(saved)             saved[0] = st             saved[1] = en     yield tuple(saved)  data = [     [(1, 5), (2, 4), (3, 6)],     [(1, 3), (2, 4), (5, 8)]     ]  for times in data:     print list(merge(times)) 
like image 148
samplebias Avatar answered Sep 20 '22 13:09

samplebias