3 changed files with 103 additions and 101 deletions
@ -0,0 +1,101 @@ |
|||||||
|
"""Функции для чистки инервалов.""" |
||||||
|
|
||||||
|
|
||||||
|
def get_smaller_interval(interval_A, interval_B) -> list: |
||||||
|
"""Если один из интервалов включает в себя другой, возвращаем |
||||||
|
меньший. Если интервалы не входят друг в друга, возвращаем пустой |
||||||
|
интервал.""" |
||||||
|
if interval_A[0] <= interval_B[0] and interval_A[1] >= interval_B[1]: |
||||||
|
return interval_B |
||||||
|
|
||||||
|
if interval_B[0] <= interval_A[0] and interval_B[1] >= interval_A[1]: |
||||||
|
return interval_A |
||||||
|
|
||||||
|
return [] |
||||||
|
|
||||||
|
|
||||||
|
def absorb_small_included_intervals(intervals: list) -> list: |
||||||
|
"""Возвращает список интервалов без вложенных интервалов. |
||||||
|
|
||||||
|
Вложенный интервал - интервал меньшего размера, полностью входящий |
||||||
|
в больший. |
||||||
|
|
||||||
|
Стоит учитывать, что функция работает только если интервалы |
||||||
|
совпадают по началу или концу, если интервалы входят друг в друга |
||||||
|
частично (пересекаются) -- здесь мы их не обрабатываем. |
||||||
|
|
||||||
|
""" |
||||||
|
# формируем список из меньших интервалов, входящих в бОльшие |
||||||
|
small_intervals = [ |
||||||
|
get_smaller_interval(interval, intervals[k]) |
||||||
|
for i, interval in enumerate(intervals) |
||||||
|
for k in range(i + 1, len(intervals)) |
||||||
|
if get_smaller_interval(interval, intervals[k]) |
||||||
|
] |
||||||
|
|
||||||
|
# в качестве результа у нас будет новый список, состоящий из |
||||||
|
# принятого списка интервалов `intervals`, за исключением входящих меньших |
||||||
|
# интервалов `small_intervals` |
||||||
|
result = [i for i in intervals if i not in small_intervals] |
||||||
|
|
||||||
|
return result |
||||||
|
|
||||||
|
|
||||||
|
def get_union_of_partly_intersecting_intervals(interval_A, interval_B) -> list: |
||||||
|
"""Если интервалы A и B пересекаются, то возвращаем новый |
||||||
|
интервал, включающий A и B.""" |
||||||
|
|
||||||
|
# если один из интервалов пустой, то пересечение будет пустым |
||||||
|
if not interval_A or not interval_B: |
||||||
|
return [] |
||||||
|
|
||||||
|
# если какой-то из интервалов имеет нулевую длину (начало=конец), |
||||||
|
# то пересечение пустое |
||||||
|
if interval_A[0] == interval_A[1] or interval_B[0] == interval_B[1]: |
||||||
|
return [] |
||||||
|
|
||||||
|
# нужно проверить, что интервалы вообще пересекаются |
||||||
|
# A и B не пересекаются, если |
||||||
|
# начало A > конец B, или если начало B > конец A |
||||||
|
if interval_A[0] > interval_B[1] or interval_B[0] > interval_A[1]: |
||||||
|
return [] |
||||||
|
|
||||||
|
# сумма интервалов: берем наименьшее начало из A и B, и наибольший конец |
||||||
|
# из A и B |
||||||
|
interval_begin = min(interval_A[0], interval_B[0]) |
||||||
|
interval_end = max(interval_A[1], interval_B[1]) |
||||||
|
return [interval_begin, interval_end] |
||||||
|
|
||||||
|
|
||||||
|
def get_extended_intervals(intervals) -> list: |
||||||
|
"""Возвращает расширенные интервалы из списка интервалов. |
||||||
|
|
||||||
|
Расширенный интервал -- это интервал, который есть сумма двух |
||||||
|
пересекающихся интервалов.""" |
||||||
|
extended_intervals = [ |
||||||
|
get_union_of_partly_intersecting_intervals(interval, intervals[k]) |
||||||
|
for i, interval in enumerate(intervals) |
||||||
|
for k in range(i + 1, len(intervals)) |
||||||
|
if get_union_of_partly_intersecting_intervals(interval, intervals[k]) |
||||||
|
] |
||||||
|
|
||||||
|
# список extended_intervals может содержать дублирующиеся |
||||||
|
# интервалы из списка intervals, поэтому мы возвращаем только |
||||||
|
# отсутствующие в intervals значения |
||||||
|
uniq_extended_intervals = [i for i in extended_intervals if i not in intervals] |
||||||
|
return uniq_extended_intervals |
||||||
|
|
||||||
|
|
||||||
|
def normilize_intervals(intervals) -> list: |
||||||
|
"""Разбивает полученный список на пары, расширяет интервалы, |
||||||
|
убирает вложенные интервалы.""" |
||||||
|
|
||||||
|
# из списка [1,2,3,4] формируем [[1,2], [3,4]] |
||||||
|
intervals_ = [intervals[i : i + 2] for i in range(0, len(intervals), 2)] |
||||||
|
|
||||||
|
# получаем расширенные интервалы |
||||||
|
extended_intervals = get_extended_intervals(intervals_) |
||||||
|
|
||||||
|
# убираем вложенные инетрвалы |
||||||
|
n_intervals = absorb_small_included_intervals(intervals_ + extended_intervals) |
||||||
|
return n_intervals |
Loading…
Reference in new issue