From e092657081e640bcab65cb031d7fc2aa32b463a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Sun, 17 Jul 2022 17:27:17 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- intervals_cleaning.py | 101 ++++++++++++++++++++++++++++++++++++++++++ readme.org | 2 +- task_3.py | 101 +----------------------------------------- 3 files changed, 103 insertions(+), 101 deletions(-) create mode 100644 intervals_cleaning.py diff --git a/intervals_cleaning.py b/intervals_cleaning.py new file mode 100644 index 0000000..38e7abb --- /dev/null +++ b/intervals_cleaning.py @@ -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 diff --git a/readme.org b/readme.org index 4c1c670..e59dd62 100644 --- a/readme.org +++ b/readme.org @@ -104,7 +104,7 @@ tutor – интервалы присутствия учителя Если ничего не выдаст в ответ -- решение работает. -Я намеренно не стал выносить часть функций по нормализации интервалов в отдельный модуль, для удобства проверки. +Функции для очистки интервалов я вынес в отдельный модуль =intervals_cleaning.py= Также в данной тестовой задаче использовать ООП я посчитал излишним, и ограничился функциональным подходом. Но если бы стояла задача решать в ООП-стиле, то ввел бы объекты: - interval (dataclass) diff --git a/task_3.py b/task_3.py index 5d955df..dcb21ed 100644 --- a/task_3.py +++ b/task_3.py @@ -1,5 +1,6 @@ """Задание на расчет интервалов, и вычисление времени, которое ученик и учитель присуствовали на уроке одновременно.""" +from intervals_cleaning import normilize_intervals tests = [ { @@ -72,91 +73,6 @@ tests = [ ] -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: - """Если интервалы А и Б пересекаются, то возвращаем новый - интервал, включающий А и Б.""" - - # если один из интервалов пустой, то пересечение будет пустым - if not interval_A or not interval_B: - return [] - - # если какой-то из интервалов имеет нулевую длину (начало=конец), - # то пересечение пустое - if interval_A[0] == interval_A[1] or interval_B[0] == interval_B[1]: - return [] - - # нужно проверить, что интервалы вообще пересекаются - # А и B не пересекаются, если - # начало А > конец B, или если начало B > конец А - if interval_A[0] > interval_B[1] or interval_B[0] > interval_A[1]: - return [] - - # сумма интервалов: берем наименьшее начало из А и Б, и наибольший конец - # из А и Б - 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 get_intersection(interval_A, interval_B) -> list: """Возвращает пересечение двух интервалов. @@ -184,21 +100,6 @@ def get_intersection(interval_A, interval_B) -> list: return [interval_begin, interval_end] -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 - - def appearance(intervals) -> int: """Возвращает время одновременного присуствия ученика и учителя на уроке в секундах."""