Browse Source

Итоговая версия

Дописал readme.
master
Дмитрий 3 years ago
parent
commit
0743ca418b
  1. 29
      readme.org
  2. 1
      requirements.txt
  3. 45
      task_2.py
  4. 31
      task_3.py

29
readme.org

@ -40,6 +40,19 @@ print(task("111111111110000000000000000"))
В:....
#+end_quote
** Решение
Для запроса к Википедии использовал библиотеку =wikipediaapi=. Для корректной работы нужно установить зависимости (лучше в виртуальное окружение).
Выполнение скрипта может занять несколько секунд. Уведомление об этом в закомментировал, чтобы вывод совпадал с требованиями задачи.
Взял на себя смелость исключить латинский алфавит из подсчета.
#+begin_src shell
pip install -r requirements.txt
python task_2.py
#+end_src
* Задача №3
Когда пользователь заходит на страницу урока, мы сохраняем время его захода. Когда пользователь выходит с урока (или закрывает вкладку, браузер – в общем как-то разрывает соединение с сервером), мы фиксируем время выхода с урока. Время присутствия каждого пользователя на уроке хранится у нас в виде интервалов. В функцию передается словарь, содержащий три списка с таймстемпами (время в секундах):
@ -80,3 +93,19 @@ tutor – интервалы присутствия учителя
assert test_answer == test['answer'], f'Error on test case {i}, got {test_answer}, expected {test["answer"]}'
#+end_src
** Решение
Задача на пересечение интервалов. Решал накладывая интервалы последовательно на ранее полученные пересечения. Входящие интервалы нормализовал (почистил от повторов и включенных интервалов, расширил пересекающиеся интервалы).
Запустить решение можно командой:
#+begin_src python
python task_3.py
#+end_src
Если ничего не выдаст в ответ -- решение работает.
Я намеренно не стал выносить часть функций по нормализации интервалов в отдельный модуль, для удобства проверки.
Также в данной тестовой задаче использовать ООП я посчитал излишним, и ограничился функциональным подходом. Но если бы стояла задача решать в ООП-стиле, то ввел бы объекты:
- interval (dataclass)
- IntervalLib для инкапсуляции методов по нормализации интервалов

1
requirements.txt

@ -0,0 +1 @@
Wikipedia-API==0.5.4

45
task_2.py

@ -1,31 +1,56 @@
"""Посчитать количество животных на каждую букву алфавита на странице 'Категория:Животные по алфавиту'.
Для запроса к вики используется библиотека wikipediaapi.
"""
import wikipediaapi
def get_all_titles_from_category(category: str) -> list:
"""Собираем названия всех страниц из `category`, формируем из них
список и возвращаем его.
"""
wiki = wikipediaapi.Wikipedia("ru")
cat = wiki.page(category)
names = [c.title() for c in cat.categorymembers]
return names
# get_counted_dict_with_first_letters
def get_count_list_by_first_letter(names: list) -> dict:
names_dict: dict = {}
for n in names:
first_letter = n[0]
count = names_dict.get(first_letter, 0)
names_dict[first_letter] = count + 1
"""Получить словарь из первых букв и их количества для каждого
элемента в `names`.
Словарь ограничен русским алфавитом (без буквы Ы). Результат имеет
вид {'А': 2, 'Б': 3, ...}.
"""
# Если изначально ограничить допустимые буквы алфавита, то можно
# избежать лишних проверок и сделать код чище
alphabet = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЭЮЯ"
names_dict: dict = {l: 0 for l in alphabet}
for name in names:
first_letter = name[0]
if first_letter not in alphabet:
continue
names_dict[first_letter] += 1
return names_dict
def main():
wiki = wikipediaapi.Wikipedia("ru")
animals = get_all_titles_from_category("Категория:Животные по алфавиту")
# animals = get_all_titles_from_category("Категория:Знаменитые животные по алфавиту")
def main(category: str):
# print("Запрос выполняется и может занять несколько секунд...")
animals = get_all_titles_from_category(category)
result: dict = get_count_list_by_first_letter(animals)
for names, count in result.items():
print(f"{names}: {count}")
if __name__ == "__main__":
main()
category = "Категория:Животные по алфавиту"
# меньшая по количеству животных категория, использовал для тестов
# category = "Категория:Знаменитые животные по алфавиту"
main(category)

31
task_3.py

@ -1,3 +1,6 @@
"""Задание на расчет интервалов, и вычисление времени, который ученик
и учитель присуствовали на уроке одновременно."""
tests = [
{
"data": {
@ -82,6 +85,7 @@ def get_smaller_interval(interval_A, interval_B) -> list:
return []
# get_intervals_without_small_included_intervals
def absorb_small_included_intervals(intervals: list) -> list:
"""Возвращает список интервалов без вложенных интервалов.
@ -93,7 +97,7 @@ def absorb_small_included_intervals(intervals: list) -> list:
частично -- мы их не обрабатываем.
"""
# формируем список из меньших интервалов, входящих в бОльшие
small_intervals = [
get_smaller_interval(interval, intervals[k])
for i, interval in enumerate(intervals)
@ -101,6 +105,9 @@ def absorb_small_included_intervals(intervals: list) -> list:
if get_smaller_interval(interval, intervals[k])
]
# в качестве результа у нас будет новый список, состоящий из
# принятого списка интервалов `intervals`, за исключением входящих меньших
# интервалов `small_intervals`
result = [i for i in intervals if i not in small_intervals]
return result
@ -137,7 +144,10 @@ def get_union_of_partly_intersecting_intervals(interval_A, interval_B) -> list:
def get_extended_intervals(intervals) -> list:
"""Возвращает расширенные интервалы из списка интервалов."""
"""Возвращает расширенные интервалы из списка интервалов.
Расширенный интервал, это интервал, который есть сумма двух
пересекающихся инетрвалов."""
extended_intervals = [
get_union_of_partly_intersecting_intervals(interval, intervals[k])
for i, interval in enumerate(intervals)
@ -145,6 +155,9 @@ def get_extended_intervals(intervals) -> list:
if get_union_of_partly_intersecting_intervals(interval, intervals[k])
]
# список extended_intervals может содержать дублирующиеся
# интервалы из списка intervals, поэтому мы возвращаем только
# отсутствующие в intevals значения
uniq_extended_intervals = [i for i in extended_intervals if i not in intervals]
return uniq_extended_intervals
@ -154,19 +167,19 @@ def get_intersection(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 []
# начало интервала = наименьший из начал интервалов А и B
# конец интервала это наименьший из концов интервалов А и B
# начало интервала это наименьший из начал интервалов А и Б
# конец интервала это наименьший из концов интервалов А и Б
interval_begin = max(interval_A[0], interval_B[0])
interval_end = min(interval_A[1], interval_B[1])
return [interval_begin, interval_end]
@ -187,7 +200,9 @@ def normilize_intervals(intervals) -> list:
return n_intervals
def appearance(intervals):
def appearance(intervals) -> int:
"""Возвращает время одновременного присуствия ученика и учителя на
уроке в секундах."""
lesson = intervals["lesson"]
pupil = normilize_intervals(intervals["pupil"])
tutor = normilize_intervals(intervals["tutor"])

Loading…
Cancel
Save