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

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

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

  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

Создайте пустой словарь lens и добавьте в него две записи: одну с ключом "Liasis papuana" и значением 4, вторую ‒ с ключом "Python reticulatus" и значением 6. Итоговый словарь должен выглядеть так:

{'Liasis papuana': 4, 'Python reticulatus' : 6}
In [ ]:
def py_dict():
    
    # YOUR CODE HERE
    
    return lens
py_dict()        
In [ ]:
assert py_dict() == {'Liasis papuana': 4, 'Python reticulatus': 6}, "Неверный ответ."

Задача 2

У питона Пети в записной книжке хранятся полные имена друзей и знакомых из разных стран. Записная книжка представляет собой словарь:

pythons = {"королевский питон Рональд" : "Уганда", 
      "карликовый питон Антониа" : "Ангола", 
      "сетчатый питон Асиф" : "Бангладеш", 
      "зеленый питон Оливер" : "Австралия", 
      "тиморский питон Николау" : "Восточный Тимор", 
      "аметистовый питон Харрисон" : "Австралия", 
      "тигровый питон Мэйли" : "Китай",
      "оливковый питон Руби" : "Австралия", 
      "белогубый питон Арис" : "Индонезия", 
      "эфиопский питон Оника" : "Мозамбик"}

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

Ожидаемый вывод на экран:

зеленый питон Оливер
оливковый питон Руби
аметистовый питон Харрисон
In [ ]:
def get_names():
    
    pythons = {"королевский питон Рональд" : "Уганда", 
          "карликовый питон Антониа" : "Ангола", 
          "сетчатый питон Асиф" : "Бангладеш", 
          "зеленый питон Оливер" : "Австралия", 
          "тиморский питон Николау" : "Восточный Тимор", 
          "аметистовый питон Харрисон" : "Австралия", 
          "тигровый питон Мэйли" : "Китай",
          "оливковый питон Руби" : "Австралия", 
          "белогубый питон Арис" : "Индонезия", 
          "эфиопский питон Оника" : "Мозамбик"}
    
    # YOUR CODE HERE

get_names()
In [ ]:
test_data = [("", 
          ["зеленый питон Оливер\n","оливковый питон Руби\n","аметистовый питон Харрисон\n"])]

for inp, out in test_data:
    with Tester([inp]) as t:
        get_names()
        assert sorted(out) == sorted(t), "Неверный ответ, проверьте соответствие Вашего вывода и ожидаемого вывода."

Задача 3

Дан словарь с записями, ключами которых являются числовые id, а значениями ‒ города.

cities = {100: 'Москва', 101: 'Санкт-Петербург', 103: 'Екатеринбург', 104: 'Пермь', 
          107: 'Красноярск', 111 : 'Киров'}

Напишите программу, которая просит пользователя ввести с клавиатуры сначала ключ, потом значение, а затем:

  • если в словаре cities есть запись с таким ключом, на экран выводится сообщение "Запись с таким ключом существует. Введите другой ключ."

  • если в словаре cities нет записи с таким ключом, в этот словарь добавляется запись с введенным ключом и значением + обновленный словарь cities выводится на экран

Пример:

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

Введите ключ: 101
Введите значение: Мурманск

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

Запись с таким ключом существует. Введите другой ключ.

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

Введите ключ: 117
Введите значение: Омск

Выходные данные (порядок записей может быть другим):

{100: 'Москва', 101: 'Санкт-Петербург', 103: 'Екатеринбург', 104: 'Пермь', 
          107: 'Красноярск', 111 : 'Киров', 117 : 'Омск'}

Обратите внимание, id должны быть целочисленными!

Подсказка: вспомните про оператор in.

In [ ]:
def add_city():
    
    cities = {100: 'Москва', 101: 'Санкт-Петербург', 103: 'Екатеринбург', 104: 'Пермь', 
              107: 'Красноярск', 111 : 'Киров'}

    # YOUR CODE HERE
add_city()
In [ ]:
from ast import literal_eval
test_data = [("101 Мурманск", 
          "Запись с таким ключом существует. Введите другой ключ."),
            ("117 Омск", {100: 'Москва', 101: 'Санкт-Петербург', 103: 'Екатеринбург', 104: 'Пермь', 
            107: 'Красноярск', 117: 'Омск', 111 : 'Киров'})]

for inp, out in test_data:
    with Tester(inp.split()) as t:
        add_city()
        if type(out) is dict:
            assert literal_eval(t[0]) == out, "Неверный ответ, был введен ключ %i, значение %s." % (int(inp.split()[0]), inp.split()[1])
        else:
            assert t[0] == out+'\n', "Неверный ответ, был введен ключ %i, значение %s." % (int(inp.split()[0]), inp.split()[1])

Задача 4

Напишите программу, которая сначала запрашивает у пользователя имена студентов через проблел, затем их оценки через пробел и создает и выводит на экран словарь, где ключами являются имена, а значениями ‒ оценки.

Пример:

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

Введите имена студентов: Анна Николай
Введите оценки студентов: 8 7

Выходные данные (порядок записей может отличаться):

{'Анна' : 8, 'Николай' : 7}
In [ ]:
def gradebook():
    # YOUR CODE HERE
gradebook()
In [ ]:
from ast import literal_eval
test_data = [("Анна Дмитрий,7 5", {'Дмитрий': 5, 'Анна': 7}),
            ("Николай Иван,10 8", {'Иван': 8, 'Николай': 10}),
            ("Мария Степан Виктор,6 5 7", {'Мария': 6, 'Степан': 5, 'Виктор': 7})]

for inp, out in test_data:
    with Tester([inp.split(",")][0] + [int(i) for i in inp.split(",")[1].split()]) as t:
        gradebook()
        assert literal_eval(t[0].strip()) == out, "Неверный ответ, были введены ключи " + inp.split(",")[0] 

Задача 5

Дан словарь results:

results = {"Best score": 25, "Champion" : "Alex"}

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

  • если число очков больше, чем текущее число очков в словаре, то она меняет значение "Best score" в results на то, которое указал пользователь, и значение "Champion" в results на имя пользователя;

  • если число очков не больше, чем текущее число очков в словаре, то программа ничего со словарем results не делает.

После чего, вне зависимости от того, был ли словарь изменен или нет, на экран выводится results. Считайте, что число очков может быть только целым.

Пример:

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

Enter your name and score: Alice 27

Выходные данные (порядок записей может отличаться):

{"Best score": 27, "Champion" : "Alice"}

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

Enter your name and score: Anton 23

Выходные данные (порядок записей может отличаться):

{"Best score": 25, "Champion" : "Alex"}
In [ ]:
def champ():
    results = {"Best score": 25, "Champion" : "Alex"}
    
    # YOUR CODE HERE
champ()
In [ ]:
from ast import literal_eval
test_data = [("Alice 27", {'Champion': 'Alice', 'Best score': 27}), 
             ("Peter 21", {'Champion': 'Alex', 'Best score': 25}), 
             ("Mark 25", {'Champion': 'Alex', 'Best score': 25}), 
             ("Ann 18", {'Champion': 'Alex', 'Best score': 25}),
             ("Sam 32", {'Champion': 'Sam', 'Best score': 32})]

for inp, out in test_data:
    with Tester([inp]) as t:
        champ()
        assert literal_eval(t[0].strip()) == out, "Неверный ответ, было введено имя %s и число очков %i" %(inp.split()[0], inp.split()[1])

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

Дан словарь, содержащий информацию по станциям метро в Новосибирске (станции в списке указаны последовательно, с севера на юг в случае Ленинской ветки, и с запада на восток в случае Дзержинской ветки).

nmetro = {"Ленинская" : ["Заельцовская", "Гагаринская", "Красный проспект", "Площадь Ленина", "Октябрьская",
               "Речной Вокзал", "Студенческая", "Площадь Маркса"], 
          "Дзержинская" : ["Площадь Гарина-Михайловского","Сибирская","Маршала Покрышкина","Березовая Роща",
          "Золотая Нива"]}

Напишите программу, которая запрашивает у пользователя сначала название текущей станции без пробела на конце, затем направление движения ('1' ‒ с севера на юг или с запада на восток, '2' ‒ с юга на север или с востока на запад) и выводит на экран название следующей станции.

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

Пример:

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

Введите название текущей станции: Гагаринская
Выберите направление движения (1 - с севера на юг или с запада на восток, 2 - с юга на север или с востока на запад): 2

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

Следующая станция: Заельцовская


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

Введите название текущей станции: Сибирская
Выберите направление движения (1 - с севера на юг или с запада на восток, 2 - с юга на север или с востока на запад): 1

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

Следующая станция: Маршала Покрышкина
In [ ]:
def metro():
    nmetro = {"Ленинская" : ["Заельцовская", "Гагаринская", "Красный проспект", "Площадь Ленина", "Октябрьская",
                   "Речной Вокзал", "Студенческая", "Площадь Маркса"], 
              "Дзержинская" : ["Площадь Гарина-Михайловского", "Сибирская", "Маршала Покрышкина", "Березовая Роща",
              "Золотая Нива"]}

    # YOUR CODE HERE
metro()
In [ ]:
test_data = [("Гагаринская,2", "Следующая станция: Заельцовская"), 
             ("Сибирская,1", "Следующая станция: Маршала Покрышкина"),
             ("Студенческая,1", "Следующая станция: Площадь Маркса"),
             ("Березовая Роща,2", "Следующая станция: Маршала Покрышкина"),
             ("Золотая Нива,2", "Следующая станция: Березовая Роща"),
             ("Площадь Гарина-Михайловского,1", "Следующая станция: Сибирская")]

for inp, out in test_data:
    
    with Tester(inp.split(",")) as t:
        metro()
        assert t[0] == out+'\n', "Неверный ответ. Было введено название %s, направление %s"%(inp.split(",")[0], inp.split(",")[1])

Задача 7 (3 балла)

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

Пользоваться можно только базовыми средствами Python: циклы и условные конструкции, методы для строк, списков, словарей.

Пример:

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

Введите текст: Люблю грозу в начале мая

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

{'м': 1, 'я': 1, 'е': 1, 'а': 3, 'н': 1, 'з': 1, 'в': 1, 'ю': 2, 'ч': 1, 'у': 1, 'р': 1, 'б': 1, 'л': 3, 'г': 1, 'о': 1}

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

Введите текст: ABBA Brilliant concert

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

{'l': 2, 't': 2, 'o': 1, 'r': 2, 'e': 1, 'b': 3, 'c': 2, 'i': 2, 'n': 2, 'a': 3}
In [ ]:
def letter_count():
    # YOUR CODE HERE
letter_count()
In [ ]:
from ast import literal_eval
test_data = [("А роза упала на лапу Азора", {'п': 2, 'а': 8, 'н': 1, 'р': 2, 'л': 2, 'з': 2, 'у': 2, 'о': 2}), 
             ("Мир Труд Май", {'й': 1, 'м': 2, 'д': 1, 'и': 1, 'а': 1, 'т': 1, 'у': 1, 'р': 2}), 
             ("ABABABCDaadd", {'b': 3, 'c': 1, 'd': 3, 'a': 5}),
             ("Ляляля турурум лмс", {'м': 2, 'я': 3, 'с': 1, 'т': 1, 'л': 4, 'у': 3, 'р': 2})]

for inp, out in test_data:
    with Tester([inp]) as t:
        letter_count()
        assert literal_eval(t[0].strip()) == out, "Неверно, был введен текст %s" % inp