Домашнее задание №2

Задачи 5-6 заимствованы из домашнего задания по курсу «Введение в программирование» (Магистерская программа «Журналистика данных», НИУ ВШЭ, 2017-18).

За разные задачи можно получить разное число баллов. Если не указано обратное, задача весит 1 балл. Максимум за ДЗ можно набрать 6 баллов. Вы можете решить больше задач, чем требуется, чтобы потренироваться.

Для предварительной проверки задания нужно сделать следующее:

  1. Скачать данный ipynb-файл на свой компьютер, открыть его в IPython Notebook/Jupyter.
  2. Активировать тесты (см. ниже).
  3. Вставить решение каждой задачи в ячейку для кода, следующую за его условием, там, где написан комментарий # YOUR CODE HERE. Отступ вашего кода должен составлять 4 пробела. Ничего не менять вокруг!
  4. Запустить ячейку, в которую вы вставили код с решением. Ввести какие-то входные данные, проверить визуально правильность вывода.
  5. Запустить следующую ячейку (в ней содержится тест). Если запуск ячейки с тестом не приводит к появлению ошибки (assertion), значит, всё в порядке, задача решена. Если приводит к появлению ошибки, значит, тест не пройден и нужно искать ошибку.

Внимание! Если в какой-то момент забыть ввести входные данные и перейти на следующую ячейку, есть риск, что Notebook перестанет откликаться. В этом случае надо перезапустить ядро: Kernel → Restart. При этом потеряются все значения переменных, но сам код останется.

Чтобы сдать ДЗ, его надо загрузить в nbgr-x в виде ipynb-файла. Получить ipynb-файл можно, выбрав в Jupyter пункт меню File → Download as... → IPython Notebook (.ipynb).

Активировать тесты

Запустите следующие ячейку, чтобы иметь возможность запускать тесты. Эту операцию нужно проделывать каждый раз, когда вы перезапускаете ядро. Если какой-то из тестов говорит NameError: name 'Tester' is not defined, нужно запустить эту ячейку ещё раз.

In [ ]:
# Фабрика тестов для проверки программ, принимающих данные через input()

from collections import deque

class Tester(object):
    def __init__(self, inp):
        self.outputs = []
        self.inputs = deque(inp)
    def print(self, *args, sep = " ", end = "\n"):
        text = sep.join(map(str, args)) + end
        newlines = text.splitlines(keepends=True)
        if self.outputs and self.outputs[-1] and self.outputs[-1][-1] != "\n" and newlines:
            self.outputs[-1] += newlines[0]
            self.outputs.extend(newlines[1:])
        else:
            self.outputs.extend(newlines)
            
    def input(self, *args):
        assert self.inputs, "Вы пытаетесь считать больше элементов, чем предусмотрено условием"
        return self.inputs.popleft()
    def __enter__(self):
        global print
        global input
        print = self.print
        input = self.input
        return self.outputs
    def __exit__(self, *args):
        global print
        global input
        del print
        del input

Задача 1

Напишите программу, которая запрашивает у пользователя любой адрес в одну строку в формате: город,улица,дом и выводит на экран список из отдельных элементов адреса (в квадратных скобках через запятую и пробел). Обратите внимание на отстутствие пробела после запятых во входных данных, это важно!

Пример.

Входные данные:

Москва,Мясницкая,20

Выходные данные:

['Москва', 'Мясницкая', '20']
In [ ]:
def address():
    # YOUR CODE HERE
address()
In [ ]:
test_data = [
    ("Москва,Мясницкая,20", ["Москва", "Мясницкая", "20"]),
    ("Санкт-Петербург,Кантемировская,3", ["Санкт-Петербург", "Кантемировская", "3"]),
    ("Пермь,Студенческая,38", ["Пермь", "Студенческая", "38"])]

for inp, out in test_data:
    with Tester([inp]) as t:
        address()
        assert len(t) == 1, "Вам нужно вывести ровно одну строку с ответом"
        assert t[0].rstrip() == repr(out), (
            "Неверный ответ для входной строки {}, "
            "ожидалось {}, получено {}".format(inp, repr(out), t[0]))

Задача 2

Дан список станций желтой ветки московского метро (упорядочены как на карте):

line = ["Третьяковская", "Марксистская", "Площадь Ильича", "Авиамоторная", "Шоссе Энтузиастов",
"Перово", "Новогиреево", "Новокосино"]

Давайте считать, что движение происходит от Третьяковской до Новокосино.

Напишите программу, которая запрашивает у пользователя название текущей станции метро (без лишнего пробела на конце) и выводит на экран сообщение вида

Следующая станция: станция.

Считайте, что пользователь знает, какая станция конечная, и не будет запрашивать станцию, следующую после Новокосино.

Пример:

Входные данные:

Введите текущую станцию: Площадь Ильича

Выходные данные:

Следующая станция: Авиамоторная

Подсказка:

Чтобы вернуть индекс определенного элемента в списке, нужно воспользоваться методом .index().

In [ ]:
def metro():
    line = ["Третьяковская", "Марксистская", "Площадь Ильича", "Авиамоторная", "Шоссе Энтузиастов",
    "Перово", "Новогиреево", "Новокосино"]
    # YOUR CODE HERE

metro()
In [ ]:
test_data = [
    ("Третьяковская", "Следующая станция: Марксистская"),
    ("Марксистская", "Следующая станция: Площадь Ильича"),
    ("Площадь Ильича", "Следующая станция: Авиамоторная"),
    ("Авиамоторная", "Следующая станция: Шоссе Энтузиастов"),
    ("Шоссе Энтузиастов","Следующая станция: Перово"),
    ("Перово", "Следующая станция: Новогиреево"),
    ("Новогиреево", "Следующая станция: Новокосино")
]

for inp, out in test_data:
    with Tester([inp]) as t:
        metro()
        assert len(t) == 1, "Вам нужно вывести ровно одну строку с ответом"
        assert t[0] == out+"\n", "Неверный ответ, была введена строка " + inp

Задача 3

Напишите программу, которая запрашивает у пользователя номер мобильного телефона в формате X-XXX-XXX-XX-XX и выводит на экран номер в формате X(XXX)XXX-XX-XX.

Пример:

Входные данные:

Введите номер телефона: 8-906-000-11-22

Выходные данные:

8(906)000-11-22
In [ ]:
def phone():
    # YOUR CODE HERE
    
phone()
In [ ]:
test_data = [
    ("8-906-000-11-22", "8(906)000-11-22"),
    ("1-234-000-17-82", "1(234)000-17-82"),
    ("7-190-904-88-00", "7(190)904-88-00")
]

for inp, out in test_data:
    with Tester([inp]) as t:
        phone()
        assert len(t) == 1, "Вам нужно вывести ровно одну строку с ответом"
        assert t[0] == out+"\n", "Неверный ответ, была введена строка " + inp

Задача 4

Дан список с названиями файлов:

files = ['file 1.txt', 'file 2.txt', 'file 6.txt', 'file 9.txt']

Напишите программу, которая переименовывает файлы в списке ‒ заменяет все пробелы на нижнее подчеркивание ‒ и выводит обновленный список files на экран.

Пример:

Входные данные:

files = ['file 1.txt', 'file 2.txt', 'file 6.txt', 'file 9.txt']

Выходные данные:

files = ['file_1.txt', 'file_2.txt', 'file_6.txt', 'file_9.txt']

Подсказка: вам потребуется цикл и метод .replace() для строк.

In [ ]:
def frename():
    files = ['file 1.txt', 'file 2.txt', 'file 6.txt', 'file 9.txt']
    # YOUR CODE HERE
    
    return files
frename()    
In [ ]:
files = ['file_1.txt', 'file_2.txt', 'file_6.txt', 'file_9.txt']

t = frename()

assert t == files,"Неверный ответ" 

Задача 5 (2 балла)

Факториалом натурального числа $n$ называется произведение всех натуральных чисел от 1 до $n$ включительно. Факториал $n$ обозначается $n!$. Например, $$ 4! = 1 \times 2 \times 3 \times 4 = 24. $$ Написать программу, запрашивающую натуральное число $n$ с клавиатуры, вычисляющую и печатающую $n!$. Использовать какие-либо библиотечные функции нельзя (то есть запрещена конструкция import).

Пример.

Входные данные:

5

Выходные данные:

120
In [ ]:
def my_fact():
    # YOUR CODE HERE

my_fact()
In [ ]:
test_data = [
    ("1", 1),
    ("2", 2),
    ("3", 6),
    ("4", 24),
    ("5", 120),
    ("10", 3628800),
    ("20", 2432902008176640000)
]

for inp, out in test_data:
    with Tester([inp]) as t:
        my_fact()
        assert len(t) == 1, "Вам нужно вывести ровно одну строку с ответом"
        assert t[0].strip() == str(out), "Неверный ответ, были введены числа " + inp
print("Хорошо, давайте теперь что-нибудь посложнее решим!")

Задача 6 (2 балла)

Числа Фибоначчии — это последовательность чисел, заданная следующим образом:

$$a_1 = 1,\quad a_2 = 1, \quad a_{k+1}=a_k+a_{k-1}$$

Ввести число k с клавиатуры и вывести $a_k$. Считать, что число k всегда больше одного. (То есть на вход никогда не будет подано число, меньшее или равное одного.)

Пример.

Входные данные:

3

Выходные данные:

2

Входные данные:

5

Выходные данные:

5

Входные данные:

6

Выходные данные:

8
In [ ]:
def fib_k():
    # YOUR CODE HERE
fib_k()
In [ ]:
test_data = [(33, 3524578),
 (87, 679891637638612258),
 (66, 27777890035288),
 (43, 433494437),
 (44, 701408733),
 (19, 4181),
 (98, 135301852344706746049),
 (65, 17167680177565),
 (32, 2178309),
 (11, 89)]
for inp, out in test_data:
    with Tester([str(inp)]) as t:
        fib_k()
        assert len(t) == 1, "Вам нужно вывести ровно одну строку с ответом"
        assert t[0].strip() == str(out), ("Неверный ответ, было "
                                          "введено число " + str(inp) + 
                                         " ожидалось " + str(out))
print("Ура, всё верно!")