From b98fd26f8e5d05a9ebda4a534d76656442277109 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: Fri, 15 Jul 2022 17:54:24 +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=20=D0=B2=20=D0=BF=D1=80=D0=BE=D1=86?= =?UTF-8?q?=D0=B5=D1=81=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- task_3.py | 123 +++++++++++++----------------------------------------- 1 file changed, 28 insertions(+), 95 deletions(-) diff --git a/task_3.py b/task_3.py index e3385f2..45116b1 100644 --- a/task_3.py +++ b/task_3.py @@ -83,9 +83,10 @@ def get_smaller_interval(interval_A, interval_B) -> list: def absorb_small_included_intervals(intervals: list) -> list: - """Если в списке есть вложенные интервалы (интревал меньшего - размера, полностью входящий в больший), то убирает их и возвращает - список без них. + """Возвращает список интервалов без вложенных интервалов. + + Вложенный интервал - интервал меньшего размера, полностью входящий + в больший. Стоит учитывать, что функция работает только если интервалы совпадают по началу или концу, если интервалы входят друг в друга @@ -100,17 +101,14 @@ def absorb_small_included_intervals(intervals: list) -> list: if get_smaller_interval(interval, intervals[k]) ] - print(f"{small_intervals=}") result = [i for i in intervals if i not in small_intervals] - print(f"{result=}") - print(f"{intervals=}") return result -def extend_partial_included_intervals(interval_A, interval_B) -> list: - """Если интервалы пересекаются, то мы заменяем их на сумму - перескающихся интервалов.""" +def get_union_of_partly_intersecting_intervals(interval_A, interval_B) -> list: + """Если интервалы А и Б пересекаются, то возвращаем новый + интервал, включающий А и Б.""" # планирую поступать по тому же принципу что и выше: добавлять # сумму в исходный список, итого получим список с пересечениями, # который потом можно прогнать через поглатитель меньших @@ -132,66 +130,26 @@ def extend_partial_included_intervals(interval_A, interval_B) -> list: return [] # сумма интервалов: наименьшее начало из А и Б, и наибольший конец + # из А и Б interval_begin = min(interval_A[0], interval_B[0]) interval_end = max(interval_A[1], interval_B[1]) - print(f"get: {[interval_A, interval_B]}") - print(f"res: {[interval_begin, interval_end]}") return [interval_begin, interval_end] -def extend_intervals(intervals) -> list: +def get_extended_intervals(intervals) -> list: + """Возвращает расширенные интервалы из списка интервалов.""" extended_intervals = [ - extend_partial_included_intervals(interval, intervals[k]) + get_union_of_partly_intersecting_intervals(interval, intervals[k]) for i, interval in enumerate(intervals) for k in range(i + 1, len(intervals)) - if extend_partial_included_intervals(interval, intervals[k]) + if get_union_of_partly_intersecting_intervals(interval, intervals[k]) ] - print(f"{extended_intervals=}") uniq_extended_intervals = [i for i in extended_intervals if i not in intervals] - print(f"{uniq_extended_intervals=}") - - result = intervals + uniq_extended_intervals - result = absorb_small_included_intervals(result) - return result - - -def find_inner_sum_of_intersections(interval_A, interval_B) -> list: - print(f"{interval_A=}") - print(f"{interval_B=}") - - # проверить, может быт интервалы входят друг в друга, и тогда - # возвращаем больший - if interval_A[0] < interval_B[0] and interval_A[1] > interval_B[1]: - return interval_A - - if interval_B[0] < interval_A[0] and interval_B[1] > interval_A[1]: - return interval_B - - if interval_A[0] == interval_B[0] and interval_A[1] == interval_B[1]: - return [] - # если один из интервалов пустой, то пересечение будет пустым - 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] + return uniq_extended_intervals -def find_intersection(interval_A, interval_B) -> list: +def get_intersection(interval_A, interval_B) -> list: # если один из интервалов пустой, то пересечение будет пустым if not interval_A or not interval_B: return [] @@ -214,65 +172,40 @@ def find_intersection(interval_A, interval_B) -> list: return [interval_begin, interval_end] -def enlarge_elapsed_intervals(intervals): - # ключ - начало, значние - конец. Если по ключу "начало" уже есть - # значение, то сохраняем max(существующее, новое) +def normilize_intervals(intervals) -> list: + """Разбивает полученный список на пары, расширяет интервалы, + убирает вложенные интервалы.""" - # чистка конечных интервалов. ключ в словаре - начало интервала. - # проходим по исходному списку и выбираем наибольшее конечное - # значение (самый поздний) из интервалов с одинаковыми началами - beginnings = {interval[0]: interval[1] for interval in intervals} - for interval in intervals: - begin = interval[0] - end = interval[1] + # из списка [1,2,3,4] формируем [[1,2], [3,4]] + intervals_ = [intervals[i : i + 2] for i in range(0, len(intervals), 2)] - beginnings[begin] = max(beginnings[begin], end) - print(f"{beginnings=}") + # получаем расширенные интервалы + extended_intervals = get_extended_intervals(intervals_) - endings = {beginnings[k]: k for k in beginnings} - for interval in intervals: - begin = interval[0] - end = interval[1] - if endings.get(end): - endings[end] = min(endings[end], begin) - - print(f"{endings=}") - result = [[endings[k], k] for k in endings] - return result + # убираем вложенные инетрвалы + n_intervals = absorb_small_included_intervals(intervals_ + extended_intervals) + return n_intervals def appearance(intervals): lesson = intervals["lesson"] - tutor = [ - intervals["tutor"][i : i + 2] for i in range(0, len(intervals["tutor"]), 2) - ] - pupil = [ - intervals["pupil"][i : i + 2] for i in range(0, len(intervals["pupil"]), 2) - ] - - pupil = extend_intervals(pupil) - - print(f"!!!{pupil=}") - - tutor = enlarge_elapsed_intervals(tutor) + pupil = normilize_intervals(intervals["pupil"]) + tutor = normilize_intervals(intervals["tutor"]) # получаем все интервалы студента на уроке pupil_on_lesson = [ - find_intersection(lesson, p) for p in pupil if find_intersection(lesson, p) + get_intersection(lesson, p) for p in pupil if get_intersection(lesson, p) ] - print(f"{pupil_on_lesson=}") # по очереди сравниваем каждый из интервалов преподавателя с # каждым из интервалов пересечения студента на уроке tutor_on_pupil = [ - find_intersection(pol, t) for t in tutor for pol in pupil_on_lesson + get_intersection(pol, t) for t in tutor for pol in pupil_on_lesson ] - print(f"{tutor_on_pupil=}") # создаем список из продолжительности каждого интервала, если он # не пустой, а затем суммируем все элементы answer = sum([intr[1] - intr[0] for intr in tutor_on_pupil if intr]) - print("----------------------------------------") return answer