OLD | NEW |
(Empty) | |
| 1 """ |
| 2 Given a list of integers, made up of (hopefully) a small number of long runs |
| 3 of consecutive integers, compute a representation of the form |
| 4 ((start1, end1), (start2, end2) ...). Then answer the question "was x present |
| 5 in the original list?" in time O(log(# runs)). |
| 6 """ |
| 7 |
| 8 import bisect |
| 9 |
| 10 def intranges_from_list(list_): |
| 11 """Represent a list of integers as a sequence of ranges: |
| 12 ((start_0, end_0), (start_1, end_1), ...), such that the original |
| 13 integers are exactly those x such that start_i <= x < end_i for some i. |
| 14 """ |
| 15 |
| 16 sorted_list = sorted(list_) |
| 17 ranges = [] |
| 18 last_write = -1 |
| 19 for i in range(len(sorted_list)): |
| 20 if i+1 < len(sorted_list): |
| 21 if sorted_list[i] == sorted_list[i+1]-1: |
| 22 continue |
| 23 current_range = sorted_list[last_write+1:i+1] |
| 24 range_tuple = (current_range[0], current_range[-1] + 1) |
| 25 ranges.append(range_tuple) |
| 26 last_write = i |
| 27 |
| 28 return tuple(ranges) |
| 29 |
| 30 |
| 31 def intranges_contain(int_, ranges): |
| 32 """Determine if `int_` falls into one of the ranges in `ranges`.""" |
| 33 tuple_ = (int_, int_) |
| 34 pos = bisect.bisect_left(ranges, tuple_) |
| 35 # we could be immediately ahead of a tuple (start, end) |
| 36 # with start < int_ <= end |
| 37 if pos > 0: |
| 38 left, right = ranges[pos-1] |
| 39 if left <= int_ < right: |
| 40 return True |
| 41 # or we could be immediately behind a tuple (int_, end) |
| 42 if pos < len(ranges): |
| 43 left, _ = ranges[pos] |
| 44 if left == int_: |
| 45 return True |
| 46 return False |
OLD | NEW |