Browse Source

Рефакторинг

master
Дмитрий 3 years ago
parent
commit
e092657081
  1. 101
      intervals_cleaning.py
  2. 2
      readme.org
  3. 101
      task_3.py

101
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

2
readme.org

@ -104,7 +104,7 @@ tutor – интервалы присутствия учителя
Если ничего не выдаст в ответ -- решение работает.
Я намеренно не стал выносить часть функций по нормализации интервалов в отдельный модуль, для удобства проверки.
Функции для очистки интервалов я вынес в отдельный модуль =intervals_cleaning.py=
Также в данной тестовой задаче использовать ООП я посчитал излишним, и ограничился функциональным подходом. Но если бы стояла задача решать в ООП-стиле, то ввел бы объекты:
- interval (dataclass)

101
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:
"""Возвращает время одновременного присуствия ученика и учителя на
уроке в секундах."""

Loading…
Cancel
Save