Python для сбора и анализа данных

Курс повышения квалификации

НИУ ВШЭ, Санкт-Петербург

Страница курса

И. В. Щуров, НИУ ВШЭ

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

Оценивание

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

Мы рекомендуем сделать по крайней мере все простые задачи (по одному-двум баллам) из каждого раздела. Пропускать простые задачи можно только в том случае, когда вы точно уверены, что легко их решите.

Проверка

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

  1. Скачать данный ipynb-файл на свой компьютер, загрузить его в Jupyter (открыть Jupyter, нажать кнопку Upload, выбрать этот ipynb-файл).
  2. Активировать тесты (см. ниже).
  3. Вставить решение каждой задачи в ячейку для кода, следующую за его условием.
  4. Запустить следующую ячейку (в ней содержится тест). Если запуск ячейки с тестом не приводит к появлению ошибки (assertion), значит, всё в порядке, задача решена. Если приводит к появлению ошибки, значит, тест не пройден и нужно искать ошибку.

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

Решения задач

Во всех задачах вам нужно написать функцию, которая принимает какие-то выходные данные (аргументы) и что-то делает. В большинстве задач функция должна вернуть какой-то результат (с помощью return). В некоторых задачах, где это явно сказано, функция должна напечатать (вывести на экран) какой-то результат (с помощью print).

Чтобы проверка задач корректно работала, нужно запустить следующую магическую ячейку. Если вы видите ошибку name Tester is not defined при запуске теста, значит, эту ячейку нужно запустить снова, потом опять запустить тест.

In [ ]:
# Магическая ячейка для запуска тестов

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. Первое знакомство. Списки

См. материалы занятия 1.

Задача 1

Написать функцию splitter(s), которая принимает на вход строку s и выводит на экран список, состоящий из слов в этой строке. Список необходимо вывести на экран просто функцией print, так, чтобы слова вывелись через запятую и пробел, в квадратных скобках.

Примеры

splitter("Hello World")
['Hello', 'World']

splitter("This is  a      very   test! Is it okay?")
['This', 'is', 'a', 'very', 'test!', 'Is', 'it', 'okay?']

Подсказка. Чтобы разбить строку по словам вам понадобится метод split, о нём можно прочитать здесь и здесь.

In [ ]:
def splitter(s):
    # YOUR CODE HERE
In [ ]:
test_data = [
    ("Hello World", ['Hello', 'World']),
    ('This is  a      very   test! Is it okay?', ['This', 'is', 'a', 'very', 
                                                  'test!', 'Is', 'it', 
                                                  'okay?']),
    ('1 22 333 4444 55555', ['1', '22','333', '4444', '55555']),
    ('One', ['One'])
]

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

Задача 2

Написать функцию no_first_last(s), которая принимает на вход строку s и возвращает список, состоящий из всех слов в этой строке, кроме первого и последнего.

В задаче не нужно использовать циклы. А вот срезы использовать нужно. Ваша функция ничего не должна печатать, она должна возвращать результат с помощью return.

Примеры

Должны выполняться следующие assert без ошибок

assert no_first_last("Hello Brave New World") == ['Brave', 'New']
assert no_first_last("This is  a      very   test! Is it okay?") == ['is', 
    'a', 'very', 'test!', 'Is', 'it']
In [ ]:
# YOUR CODE HERE
In [ ]:
test_data = [
    ("Hello Brave New World", ['Brave', 'New']),
    ('This is  a      very   test! Is it okay?', ['is', 'a', 'very', 
                                                  'test!', 'Is', 'it']),
    ('1 22 333 4444 55555', ['22','333', '4444']),
    ('One', []),
    ('One Two', []),
    ('One Two Three', ['Two'])
]

for inp, out in test_data:
    assert no_first_last(inp) == out, (
        "Неверный ответ для входной строки {}, "
        "ожидалось {}".format(inp, out))
print("Отлично!")

Задача 3

Напишите функцию word_and_number(s, n), принимающую на вход строку s, и целое число n. Функция должна разделить строку на слова и вернуть n'ое слово. Счёт начинать с единицы, то есть если в качестве n было введено число 1, вывести первое слово.

В задаче не нужно использовать циклы.

Примеры

Должны выполняться следующие assert без ошибок:

assert word_and_number("Hello Brave New World", 3) == "New"
assert word_and_number("This is  a      very   test! Is it okay?", 1) == "This"
In [ ]:
# YOUR CODE HERE
In [ ]:
test_data = [
    ["This", "is", "a", "test"],
    ["Hello"],
    ["One", "two", "three"],
    ["One", "Two"] * 100
]

for inp in test_data:
    for i in range(len(inp)):
        assert word_and_number(" ".join(inp), i + 1) == inp[i]
print("Всё верно")

Задача 4

Напишите функцию split_n_add(s1, s2), принимающую на вход две строки. Разбейте первую строку на слова и добавьте в конец получившегося списка вторую строку целиком. Верните получившийся список.

Пример

assert split_n_add("Hello Brave New World", "This is a test") == ['Hello', 
    'Brave', 'New', 'World', 'This is a test']

Подсказка. Здесь можно использовать метод .append или конкатенацию списков, см. лекцию про списки.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert split_n_add("Hello Brave New World", "This is a test") == ['Hello', 
        'Brave', 'New', 'World', 'This is a test']
assert split_n_add("A", "B") == ["A", "B"]
assert split_n_add("A B", "B") == ["A", "B", "B"]
assert split_n_add("B", "A B") == ["B", "A B"]

Задача 5

Напишите функцию right_to_left(s), принимающую на вход строку s. Создайте новую строку, получающуюся из s перестановкой слов в обратном порядке, и верните её.

В этой задаче не нужно использовать циклы. Используйте метод списка .reverse(): изучите самостоятельно, как он работает.

Примеры см. в тесте

In [ ]:
# YOUR CODE HERE
In [ ]:
assert right_to_left("Hello Brave New World") == "World New Brave Hello"
assert right_to_left("This is a test") == "test a is This"
assert right_to_left("This") == "This"

Часть 2: цикл for

См. материалы занятия 2.

Задача 6

Функция hello_names(s) получает на вход строку s, содержащую имена, разделённые пробелами. Для каждого имени вывести на экран строчку

Hello, <имя>!

Всего должно быть выведено столько строк, сколько имён написано в строке.

Пример

hello_names("Alice Bob Daniel")

Вывод

Hello, Alice!
Hello, Bob!
Hello, Daniel!

Подсказка. Здесь нужно использовать цикл for. Обратите внимание на восклицательный знак в конце и пробелы — после запятой пробел нужен, до восклицательного знака — нет. Вам поможет добиться такого эффекта параметр sep у функции print. Попробуйте, например, запустить print("a", "b", "c", sep="!!").

In [ ]:
# YOUR CODE HERE
In [ ]:
from itertools import zip_longest
import re
names = ['Alice', 'Bob', 'Daniel', 'C3PO', 'Tyrion']
for i in range(1, len(names) + 1):
    cur_names = " ".join(names[:i])
    with Tester([cur_names]) as t:
        hello_names(cur_names)
        assert len(t) == i
        for out, name in zip_longest(t, names[:i]):
            assert re.match("Hello, " + name + "!$", out.rstrip()), "Something wrong with name " + \
                                                    name + ", expected 'Hello, " + name + \
                                                    "', got '" + out + "'"
print("Очень хорошо! Вы справились!")

Задача 7

Напишите функцию print_range(A, B), принимающую на вход два целых числа A и B (при этом A≤B). Функция выводит все целые числа от A до B включительно в столбик.

Пример

print_range(3, 6)

Вывод

3
4
5
6

Подсказка. Помните о том, что range всегда включает свою левую границу, но не включает правую.

In [ ]:
# YOUR CODE HERE
In [ ]:
test_data = [
    ["2 4", "2 3 4"],
    ["1 10", "1 2 3 4 5 6 7 8 9 10"],
    ["0 0", "0"],
    ["-5 0", "-5 -4 -3 -2 -1 0"],
    ["1 1", "1"],
    ["0 100", '0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100']
]

for inp, out in test_data:
    with Tester(inp.split()) as t:
        print_range(*map(int, inp.split()))
        assert len(t) == len(out.split()), 'Вы вывели неверное количество чисел для входных данных ' + inp
        for o, e in zip(t, out.split()):
            assert int(o) == int(e), "Неверный ответ для входных данных " + inp

print("Это было просто да? Дальше будет интереснее :)")

Задача 8

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

Примеры см. в тесте.

Подсказка. Чтобы превратить строку в целое число, нужно использовать функцию int.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert s_prod("9 2 5") == 90
assert s_prod("1") == 1
assert s_prod("0 10") == 0
assert s_prod("1 2 3 4 5 6 7 8 9 10") == 3628800
assert s_prod("-1 -1 -1 -1 -1") == -1

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

Необязательная задача

Функция mult_table(n) принимает на вход целое число n и выводит таблицу умножения от 1 до n включительно, как показано в примере. Напишите такую функцию. Допустимо, чтобы каждая строка заканчивалась пробелом.

Пример

mult_table(5)

1 2 3 4 5 
2 4 6 8 10 
3 6 9 12 15 
4 8 12 16 20 
5 10 15 20 25 

Подсказка. Вам понадобятся вложенные циклы — цикл внутри цикла. Также может оказаться полезным следующее знание: print по умолчанию добавляет в конец строки символ перевода строки (то есть каждый следующий print печатает с новой строки). Чтобы он этого не делал, можно добавить ему именованный аргумент end. Например, попробуйте запустить следующий код:

print("Hello", end="!!!")
print("World")
In [ ]:
# YOUR CODE HERE
In [ ]:
test_data = [(1, ['1 \n']),
 (4, ['1 2 3 4 \n', '2 4 6 8 \n', '3 6 9 12 \n', '4 8 12 16 \n']),
 (7,
  ['1 2 3 4 5 6 7 \n',
   '2 4 6 8 10 12 14 \n',
   '3 6 9 12 15 18 21 \n',
   '4 8 12 16 20 24 28 \n',
   '5 10 15 20 25 30 35 \n',
   '6 12 18 24 30 36 42 \n',
   '7 14 21 28 35 42 49 \n']),
 (10,
  ['1 2 3 4 5 6 7 8 9 10 \n',
   '2 4 6 8 10 12 14 16 18 20 \n',
   '3 6 9 12 15 18 21 24 27 30 \n',
   '4 8 12 16 20 24 28 32 36 40 \n',
   '5 10 15 20 25 30 35 40 45 50 \n',
   '6 12 18 24 30 36 42 48 54 60 \n',
   '7 14 21 28 35 42 49 56 63 70 \n',
   '8 16 24 32 40 48 56 64 72 80 \n',
   '9 18 27 36 45 54 63 72 81 90 \n',
   '10 20 30 40 50 60 70 80 90 100 \n']),
 (13,
  ['1 2 3 4 5 6 7 8 9 10 11 12 13 \n',
   '2 4 6 8 10 12 14 16 18 20 22 24 26 \n',
   '3 6 9 12 15 18 21 24 27 30 33 36 39 \n',
   '4 8 12 16 20 24 28 32 36 40 44 48 52 \n',
   '5 10 15 20 25 30 35 40 45 50 55 60 65 \n',
   '6 12 18 24 30 36 42 48 54 60 66 72 78 \n',
   '7 14 21 28 35 42 49 56 63 70 77 84 91 \n',
   '8 16 24 32 40 48 56 64 72 80 88 96 104 \n',
   '9 18 27 36 45 54 63 72 81 90 99 108 117 \n',
   '10 20 30 40 50 60 70 80 90 100 110 120 130 \n',
   '11 22 33 44 55 66 77 88 99 110 121 132 143 \n',
   '12 24 36 48 60 72 84 96 108 120 132 144 156 \n',
   '13 26 39 52 65 78 91 104 117 130 143 156 169 \n'])]

for inp, out in test_data:
    with Tester([str(inp)]) as t:
        mult_table(inp)
        line_t = "".join(t)
        t = line_t.splitlines()
        assert len(t) == len(out), "Неверное количество строк в выводе"
        for l_test, l_out in zip(t, out):
            assert len(l_test.split()) == len(l_out.split()), \
                "Неверное количество элементов в строке " + l_out
            for el_test, el_out in zip(l_test.split(), l_out.split()):
                assert el_test == el_out, "Ошибка {} != {}".format(l_test, 
                                                                   l_out)
print("Теперь вы можете печатать тетрадки для школьников!")

Задача 10 (4 балла)

Необязательная задача

Не пользуясь библиотечными функциями, напишите функцию pascal_triangle(n), которая для данного целого n, выводит на экран первые $n$ строк треугольника Паскаля. Элементы должны быть разделены пробелами. Допустимо наличие пробела в конце строки.

Пример

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

5

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

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
In [ ]:
# YOUR CODE HERE
In [ ]:
test_data = zip(range(1, 20), [['1\n'],['1\n', '1 1\n'], ['1\n', '1 1\n', '1 2 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n', '1 11 55 165 330 462 462 330 165 55 11 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n', '1 11 55 165 330 462 462 330 165 55 11 1\n', '1 12 66 220 495 792 924 792 495 220 66 12 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n', '1 11 55 165 330 462 462 330 165 55 11 1\n', '1 12 66 220 495 792 924 792 495 220 66 12 1\n', '1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n', '1 11 55 165 330 462 462 330 165 55 11 1\n', '1 12 66 220 495 792 924 792 495 220 66 12 1\n', '1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1\n', '1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n', '1 11 55 165 330 462 462 330 165 55 11 1\n', '1 12 66 220 495 792 924 792 495 220 66 12 1\n', '1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1\n', '1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1\n', '1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n', '1 11 55 165 330 462 462 330 165 55 11 1\n', '1 12 66 220 495 792 924 792 495 220 66 12 1\n', '1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1\n', '1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1\n', '1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1\n', '1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n', '1 11 55 165 330 462 462 330 165 55 11 1\n', '1 12 66 220 495 792 924 792 495 220 66 12 1\n', '1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1\n', '1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1\n', '1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1\n', '1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1\n', '1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1\n'], ['1\n', '1 1\n', '1 2 1\n', '1 3 3 1\n', '1 4 6 4 1\n', '1 5 10 10 5 1\n', '1 6 15 20 15 6 1\n', '1 7 21 35 35 21 7 1\n', '1 8 28 56 70 56 28 8 1\n', '1 9 36 84 126 126 84 36 9 1\n', '1 10 45 120 210 252 210 120 45 10 1\n', '1 11 55 165 330 462 462 330 165 55 11 1\n', '1 12 66 220 495 792 924 792 495 220 66 12 1\n', '1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1\n', '1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1\n', '1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1\n', '1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1\n', '1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1\n', '1 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 153 18 1\n']])
for inp, out in test_data:
    with Tester([str(inp)]) as t:
        pascal_triangle(inp)
        line_t = "".join(t)
        t = line_t.splitlines()
        assert len(t) == len(out), "Неверное количество строк в выводе"
        for l_test, l_out in zip(t, out):
            assert len(l_test.split()) == len(l_out.split()), \
                "Неверное количество элементов в строке " + l_out
            for el_test, el_out in zip(l_test.split(), l_out.split()):
                assert el_test == el_out, "Ошибка: {} != {}".format(
                l_test, l_out)
print("Ну как вам треугольничек? Красивый, правда?")

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

Функция first_last_word(s) принимает на вход строку, состоящую из нескольких предложений. Каждое предложение заканчивается точкой. Все слова разделены пробелами. После точек тоже ставится пробел (если это не самая последняя точка). Никаких других знаков препинания нет. Для каждого предложения вывести его первое и последнее слово.

Пример

first_last_word("One two three. Hello World. This is just a test.")

One three
Hello World
This test

Подсказка. Если передать методу .split() параметр, то он будет использовать его в качестве разделителя. Например, попробуйте посмотреть, что выдаст "Hello, World! This is a test! Okay?".split("!"). Чтобы избавиться от пробелов в начале и конце строки можно использовать метод .strip().

In [ ]:
# YOUR CODE HERE
In [ ]:
test_data = [("One two three. Hello World. This is just a test.",
              "One three", "Hello World", "This test"),
            ("One two.", "One two"),
            ("One two three.", "One three"),
            (" ".join(("Hello world " * 10).strip() + "." 
                     for _ in range(100)),) + ("Hello world", ) * 100]
for testcase in test_data:
    with Tester([testcase[0]]) as t:
        first_last_word(testcase[0])
        assert len(t) == len(testcase) - 1
        assert [s.strip() for s in t] == list(testcase[1:]), (
            [s.strip() for s in t], testcase[1:])

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

Функция digits_to_string(n) принимает на вход целое положительное число n и возвращает строку, в которой все цифры n записаны словами. Результат записывается с большой буквы, разделенный пробелами.

Запрещено использовать оператор if.

Примеры в тесте.

assert(123) == "One two three"

assert(5023) == "Five zero two three"

Подсказка В цикле for строка будет вести как список, состоящий из отдельных символов. Превратить число в строку можно с помощью str. Чтобы сделать первую букву строки большой, используйте метод .capitalize().

In [ ]:
# YOUR CODE HERE
In [ ]:
test_data = [(1, "One"),
            (12, "One two"),
            (123, "One two three"),
            (1234567890, "One two three four five six seven eight nine zero"),
            (90912, "Nine zero nine one two")]
for inp, out in test_data:
    assert digits_to_string(inp) == out

Часть 3. Проверка условий и больше о функциях

См. материалы занятия 3.

Задача 13 (1 балл)

Написать функцию is_odd(n), проверяющую, является ли данное число n нечётным. Она должна возвращать True, если число нечётное, и False, если чётное. Функция не должна ничего выводить на экран!

Подсказка. Здесь можно использовать if, но можно и не использовать. :)

In [ ]:
# YOUR CODE HERE
In [ ]:
assert(is_odd(1))
assert(not is_odd(2))
assert(not is_odd(0))
assert(is_odd(101))
with Tester([]) as t:
    is_odd(1)
    assert len(t) == 0, "функция ничего не должна печатать"
print("Отлично! Едем дальше.")

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

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

In [ ]:
# YOUR CODE HERE
In [ ]:
assert(num_div(1) == 1)
assert(num_div(2) == 2)
assert(num_div(3) == 2)
assert(num_div(100) == 9)
assert(num_div(1000) == 16)
assert(num_div(139) == 2)
assert(num_div(1289237) == 2)
print("Похоже на правду!")

Задача 15 (1 балл)

Написать функцию is_prime(n), проверяющую, является ли данное число n простым. Она должна вернуть True, если является, и False, если не является.

Примечание. Можете использовать ранее написанную функцию num_div(n). (Вопрос: Является ли это самым эффективным способом решения данной задачи?)

In [ ]:
# YOUR CODE HERE
In [ ]:
assert(is_prime(2) and 
       is_prime(3) and 
       is_prime(139) and 
       is_prime(617) and 
       is_prime(293) and 
       not is_prime(12) and 
       not is_prime(13*7))
print("Отлично! Давайте сделаем что-нибудь посложнее.")

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

Написать функцию med3(x,y,z), возвращающую медиану из чисел x, y, z (то есть то из этих чисел, которое будет стоять посередине, если их упорядочить). Пользоваться какими-либо библиотечными функциями нельзя! Сортировкой тоже пользоваться нельзя.

In [ ]:
# YOUR CODE HERE
In [ ]:
from itertools import permutations
def test_med3(x,y,z,m):
    for t in permutations([x,y,z]):
        assert(med3(*t) == m)
test_med3(1,1,1,1)
test_med3(1,1,2,1)
test_med3(1,2,2,2)
test_med3(1,2,3,2)
test_med3(0,1,2,1)
test_med3(100,200,300,200)
test_med3(100,101,1000,101)
print("Ура! Получилось!")

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

Написать функцию is_increasing(lst, strict), проверяющую, является ли список lst возрастающим. Если параметр strict установлен в True, нужно проверять строгое возрастание, иначе нестрогое. Иными словами, функция должна возвращать True, если каждый элемент списка не меньше (если strict установлен в False) или строго больше (если strict установлен в True) предыдущего, и False в противном случае. Если strict не указан, функция должна считать, что strict установлен в True.

Это важная задача. Сделайте её!

In [ ]:
# YOUR CODE HERE
In [ ]:
assert is_increasing([1, 2, 3, 4, 5]) == True
assert is_increasing([1, 10, 15, 16, 17]) == True
assert is_increasing([5]) == True
assert is_increasing([5, 5]) == False
assert is_increasing([5, 6, 7, 7]) == False
assert is_increasing([5, 6, 7, 8, 7]) == False
assert is_increasing([2, 1, 5, 6]) == False

assert is_increasing([1, 1], strict=True) == False
assert is_increasing([1, 1], strict=False) == True

assert is_increasing([1, 2, 3, 3], strict=True) == False
assert is_increasing([1, 2, 3, 3], strict=False) == True
assert is_increasing([1, 2, 3, 2], strict=False) == False
assert is_increasing(list(range(10000))) == True

Задача 18

Написать функцию average(list_of_numbers), которая принимает на вход список чисел и возвращает его среднее арифметическое.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert average([5]) == 5
assert average([0]) == 0
assert average([4, 6]) == 5
assert average([1, 2, 3, 4, 5, 6, 7, 8, 9]) == 5
assert average([1, 100, 200, 300]) == 150.25

Задача 19

Написать функцию average_of, которая принимает на вход несколько чисел и возвращает их среднее арифметическое. В отличие от предыдущей задачи, здесь функция должна принимать на вход не один список, а несколько чисел. Примеры см. в тесте.

Подсказка. Можно написать функцию, принимающую переменное число аргументов. Как это сделать написано тут.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert average_of(5) == 5
assert average_of(0) == 0
assert average_of(4, 6) == 5
assert average_of(1, 2, 3, 4, 5, 6, 7, 8, 9) == 5
assert average_of(1, 100, 200, 300) == 150.25

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

Написать функцию variance(numbers, unbiased), принимающую на вход список вещественных чисел numbers и булевскую переменную unbiased и возвращающую выборочную дисперсию для numbers. Если параметр unbiased установлен в True, должна возвращаться исправленная (несмещённая) выборочная дисперсия. Если параметр unbiased не указан, он считается установленным в True. Вы можете пользоваться ранее созданными функциями, но не можете пользоваться никакими библиотеками.

Внимание. Если тест работает слишком медленно, вероятно, это означает, что ваш код не оптимален и может быть не принят проверяющей системой. Подумайте о том, как избежать повторного выполнения одних и тех же действий.

In [ ]:
# YOUR CODE HERE
In [ ]:
import numpy as np
np.random.seed(42)
for i in [3, 10, 100, 1000, 10000]:
    num = np.random.uniform(size=i)
    assert np.isclose(variance(num), np.var(num, ddof=1))
    assert np.isclose(variance(num, unbiased=False), np.var(num, ddof=0))

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

Итоговая оценка вычисляется по формуле: $\text{накопленная} \times 0.75 + \text{экзамен} \times 0.25$ и округляется до целого числа. Если оценка имеет вид «целое + 1/2», то она округляется вверх (то есть до «целое + 1»), в остальном округлением происходит к ближайшему целому. Написать функцию final_grade(acc, exam), которая бы принимала на вход накопленную и экзаменационную оценки и возвращала итоговую оценку.

Подсказка. Есть функция round, но она округляет числа вида «целое + 1/2» к ближайшему чётному.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert final_grade(1, 2) == 1
assert final_grade(acc=1, exam=2) == 1
assert final_grade(exam=2, acc=1) == 1
assert final_grade(1, 5) == 2
assert final_grade(0, 0) == 0
assert final_grade(0, 1) == 0
assert final_grade(0, 2) == 1
assert final_grade(0, 3) == 1
assert final_grade(0, 4) == 1
assert final_grade(0, 5) == 1
assert final_grade(0, 6) == 2
assert final_grade(0, 7) == 2
assert final_grade(0, 8) == 2
assert final_grade(0, 9) == 2
assert final_grade(1, 0) == 1
assert final_grade(1, 1) == 1
assert final_grade(1, 2) == 1
assert final_grade(1, 3) == 2
assert final_grade(1, 4) == 2
assert final_grade(1, 5) == 2
assert final_grade(1, 6) == 2
assert final_grade(1, 7) == 3
assert final_grade(1, 8) == 3
assert final_grade(1, 9) == 3
assert final_grade(2, 0) == 2
assert final_grade(2, 1) == 2
assert final_grade(2, 2) == 2
assert final_grade(2, 3) == 2
assert final_grade(2, 4) == 3
assert final_grade(2, 5) == 3
assert final_grade(2, 6) == 3
assert final_grade(2, 7) == 3
assert final_grade(2, 8) == 4
assert final_grade(2, 9) == 4
assert final_grade(3, 0) == 2
assert final_grade(3, 1) == 3
assert final_grade(3, 2) == 3
assert final_grade(3, 3) == 3
assert final_grade(3, 4) == 3
assert final_grade(3, 5) == 4
assert final_grade(3, 6) == 4
assert final_grade(3, 7) == 4
assert final_grade(3, 8) == 4
assert final_grade(3, 9) == 5
assert final_grade(4, 0) == 3
assert final_grade(4, 1) == 3
assert final_grade(4, 2) == 4
assert final_grade(4, 3) == 4
assert final_grade(4, 4) == 4
assert final_grade(4, 5) == 4
assert final_grade(4, 6) == 5
assert final_grade(4, 7) == 5
assert final_grade(4, 8) == 5
assert final_grade(4, 9) == 5
assert final_grade(5, 0) == 4
assert final_grade(5, 1) == 4
assert final_grade(5, 2) == 4
assert final_grade(5, 3) == 5
assert final_grade(5, 4) == 5
assert final_grade(5, 5) == 5
assert final_grade(5, 6) == 5
assert final_grade(5, 7) == 6
assert final_grade(5, 8) == 6
assert final_grade(5, 9) == 6
assert final_grade(6, 0) == 5
assert final_grade(6, 1) == 5
assert final_grade(6, 2) == 5
assert final_grade(6, 3) == 5
assert final_grade(6, 4) == 6
assert final_grade(6, 5) == 6
assert final_grade(6, 6) == 6
assert final_grade(6, 7) == 6
assert final_grade(6, 8) == 7
assert final_grade(6, 9) == 7
assert final_grade(7, 0) == 5
assert final_grade(7, 1) == 6
assert final_grade(7, 2) == 6
assert final_grade(7, 3) == 6
assert final_grade(7, 4) == 6
assert final_grade(7, 5) == 7
assert final_grade(7, 6) == 7
assert final_grade(7, 7) == 7
assert final_grade(7, 8) == 7
assert final_grade(7, 9) == 8
assert final_grade(8, 0) == 6
assert final_grade(8, 1) == 6
assert final_grade(8, 2) == 7
assert final_grade(8, 3) == 7
assert final_grade(8, 4) == 7
assert final_grade(8, 5) == 7
assert final_grade(8, 6) == 8
assert final_grade(8, 7) == 8
assert final_grade(8, 8) == 8
assert final_grade(8, 9) == 8
assert final_grade(9, 0) == 7
assert final_grade(9, 1) == 7
assert final_grade(9, 2) == 7
assert final_grade(9, 3) == 8
assert final_grade(9, 4) == 8
assert final_grade(9, 5) == 8
assert final_grade(9, 6) == 8
assert final_grade(9, 7) == 9
assert final_grade(9, 8) == 9
assert final_grade(9, 9) == 9

Задача 22 (4 балла)

Это необязательная задача. Её можно смело пропустить.

Рассмотрим некоторое арифметическое выражение, которое может содержать скобки — квадратные или круглые. Каждая скобка должна корректно закрываться скобкой такого же типа. Например, 5 * [1 + 2 + (3 + 4) + 5] — корректное выражение, а выражение 4 + (2 + некорректное, потому что скобка открылась и не закрылась. Также некорректным будет выражение [1 + (2 + 3] + 4), потому что, например, первая квадратная скобка должна была закрыться также квадратной, а закрылась круглой.

Написать функцию check_brackets(expr), принимающую на вход строку, содержащую выражение, и возвращающую True, если выражение корректное, и False в противном случае.

Подсказка. Вам нужно запоминать, в каком порядке какие скобки открывались. Когда скобка корректно закрылась, она вас больше не интересует.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert check_brackets('5 * [1 + 2 + (3 + 4) + 5]')
assert not check_brackets('4 + (2 + ')
assert not check_brackets('[1 + (2 + 3] + 4)')
assert check_brackets('[]()[][[([(([]))])]]')
assert not check_brackets(']')
assert not check_brackets(')')
assert not check_brackets('[)]')
assert not check_brackets('[)()]')
assert not check_brackets('[)](')
assert not check_brackets("[[([(]))]]")
assert not check_brackets('[')
assert not check_brackets('(')
assert not check_brackets('(' * 100 + ')' * 99)
assert  check_brackets('(' * 1000 + ')' * 1000)
assert not check_brackets('([' + '(' * 998 + ')' * 909 + ']')

Задача 23

Написать функцию elementwise_concat(words1, words2, sep), принимающую на вход два списка строк words1 и words2 и строку sep, и возвращающую список, составленный следующим образом: его первый элемент — это первый элемент списка words1, сконкатенированный с sep и затем с первым элементом words2, второй элемент — второй элемент words1, сконкатенированный с sep, а затем со вторым элементом words2 и т.д. Например, elementwise_concat(['Harry', 'Ron'], ['Potter', 'Weasley'], sep='+') должен вернуть список ['Harry+Potter', 'Ron+Weasley']. Если параметр sep не указан, в качестве разделителя должна использоваться пустая строка. То есть elementwise_concat(['Harry', 'Ron'], ['Potter', 'Weasley']) должен возвращать ['HarryPotter', 'RonWeasley']

Подсказка. Приятнее всего эту задачу решать с помощью list comprehensions).

In [ ]:
# YOUR CODE HERE
In [ ]:
assert elementwise_concat(['Harry', 'Ron'], 
                          ['Potter', 'Weasley']) == ['HarryPotter', 
                                                     'RonWeasley']
assert elementwise_concat(['a'], ['bb']) == ['abb']
assert elementwise_concat(map(str, range(10)),
                          map(str, range(9, -1, -1))) == ['09', '18', '27', 
                                                          '36', '45', '54', 
                                                          '63', '72', '81', 
                                                          '90']
assert elementwise_concat(['Harry', 'Ron'], 
                          ['Potter', 'Weasley'], sep="+") == ['Harry+Potter', 
                                                              'Ron+Weasley']
assert elementwise_concat(['Harry', 'Harry'], ['Ron', 'Hermiona'], 
                          sep=' and ') == ['Harry and Ron', 
                                           'Harry and Hermiona']

Часть 4.1. Словари

См. материалы занятия 4.

Задача 24 (1 балл)

Написать функцию Dan_5(grades), принимающую на вход словарь grades, добавляющую в него запись с ключом "Dan" и значением 5 и возвращающую этот словарь.

Подсказка. Код должен начинаться со строчки

def Dan_5(grades):

и заканчиваться строчкой

return grades
In [ ]:
# YOUR CODE HERE
In [ ]:
assert Dan_5({}) == {'Dan': 5}
assert Dan_5({'Dan': 3}) == {'Dan': 5}
assert Dan_5({'Alice': 2}) == {'Alice': 2, 'Dan': 5}
assert Dan_5({1:2,3:4,'Dan':'Dan',5:'Dan'}) == {1:2,3:4,'Dan':5, 5:'Dan'}

Задача 25 (1 балл)

Написать функцию Dan_plus_1(grades), которая принимает на вход словарь grades, после чего меняет его следующим образом. Если в этом словаре имеется запись с ключом "Dan", то её значение должно быть увеличено на 1. Если такой записи нет, она должна быть создана и ей должно быть присвоено значение 1. Функция должна вернуть получающийся словарь. Гаранируется, что в словаре grades все ключи являются строками, а все значения — целыми числами (проверять это не нужно).

Подсказка. Здесь можно обойтись без if с помощью .get.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert Dan_plus_1({}) == {'Dan': 1}
assert Dan_plus_1({'Dan': 3}) == {'Dan': 4}
assert Dan_plus_1({'Alice': 4})=={'Alice': 4,'Dan': 1}
assert Dan_plus_1({'Alice': 4, 'Bob': 3, 'Dan': 5}) == {'Alice': 4, 'Bob': 3, 
                                                        'Dan': 6}

Задача 26 (1 балл)

Написать функцию what_about_Dan(grades), которая принимает на вход словарь grades, после чего возвращает строку, в зависимости от значения записи с ключом "Dan". Если такой записи нет, функция должна вернуть строку "Don't know Dan". Если такая запись есть и её значением является число, большее 3, функция должна вернуть строку "Dan is fine". Если такая запись есть и её значением является число, меньшее или равное 3, то функция должна вернуть строку "Dan needs help".

In [ ]:
# YOUR CODE HERE
In [ ]:
assert what_about_Dan({}) == "Don't know Dan"
assert what_about_Dan({"Dan": 1}) == "Dan needs help"
assert what_about_Dan({"Dan": 5}) == "Dan is fine"
assert what_about_Dan({"Dan": 1, 'Claudia': 3}) == "Dan needs help"
assert what_about_Dan({"Dan": 5, 'Claudia': 5}) == "Dan is fine"
assert what_about_Dan({"Dan": 1, 'Alice': 3, 'Claudia': 8}) == \
                      "Dan needs help"
assert what_about_Dan({"Dan": 5, 'Alice': 4, 'Claudia': 9}) == "Dan is fine"
assert what_about_Dan({'Claudia': 3}) == "Don't know Dan"

Задача 27 (1 балл)

Написать функцию are_there_more_4(grades), проверяющую, есть ли среди значений словаря grades хоть одно число больше 4. Функция должна возвращать True, если такое значение есть, и False в противном случае. Гарантируется, что в словаре есть хотя бы одна запись и значениями словаря являются только числа.

Подсказка. Функция max принимает на вход список (или что-то подобное) и выдаёт максимальный элемент. Например, max([1, 3, 2]) вернёт 3. Её можно использовать в этой задаче и обойтись без циклов. Впрочем, можете решить её и с циклами.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert are_there_more_4({1: 2,3: 3}) is False
assert are_there_more_4({5: 3, 2: 3, 4: 1}) is False
assert are_there_more_4({6: 5}) is True
assert are_there_more_4({'Alice': 3, 'Bob': 4}) is False
assert are_there_more_4({'Alice': 4, 'Bob': 5, "Dan": 3}) is True
assert are_there_more_4({6: 8}) is True
assert are_there_more_4({'Alice': 4, 'Bob': 9, "Dan": 3}) is True

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

Написать функцию flatten_dict(d), принимающую на вход словарь d и возвращающую список, в который записаны последовательно ключи и значения словаря d (порядок следования ключей не важен, но после каждого ключа должно идти значение, которое ему соответствует). Например, flatten_dict({'Alice': 1, 'Bob': 2}) может вернуть список ['Alice', 1, 'Bob', 2] или список ['Bob', 2, 'Alice', 1].

In [ ]:
# YOUR CODE HERE
In [ ]:
def checkdict(d):
    l = flatten_dict(d)
    assert set(l[::2]) == set(d.keys())
    for i in range(0, len(l),2):
        assert d[l[i]] == l[i+1]
checkdict({})
checkdict({'Alice': 1, 'Bob': 2})
checkdict({'Alice': 1})
checkdict({2: 1, 3: 1, 4: 1})
checkdict({'Alice': 'Bob', 1: 2, 'Jein': 'Bob'})
del checkdict

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

Написать функцию countlen(words), принимающую на вход список строк, а возвращающую словарь, ключами которого являются строки из списка words, а значениями — их длины (в символах). Например, countlen(['hello', 'world!']) возвращает словарь {'hello':5, 'world!':6}.

Подсказка. Чтобы создать пустой словарь, можно использовать пустые фигурные скобки {}.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert countlen(['Alice'])=={'Alice':5}
assert countlen([])=={}
assert countlen(['this', 'is', 'a', 'table'])=={'this':4, 'is':2, 'a':1, 'table': 5}
assert countlen(['z'*100])=={'z'*100:100}

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

Необязательная задача.

Напишите функцию stats(words), принимающую на вход список строк и возвращающую самое часто встречающееся слово. Если таких слов несколько, следует вернуть то из них, которое в списке встречается первым.

Например, stats(["qqq", "hello", "hello", "world"]) должна вернуть строчку "hello", а stats(["qqq", "a", "b", "b", "a", "c"]) должна вернуть строку "a". Использовать какие-либо библиотеки нельзя.

Подсказка. Казалось бы, причём здесь словари?

In [ ]:
# YOUR CODE HERE
In [ ]:
def checkstats(i, o):
    assert stats(i.split())==o

checkstats("apple orange banana banana orange", 'orange')
checkstats("""q w e r t y u i o p
a s d f g h j k l
z x c v b n m""", 'q')
checkstats("""vqcg vqcg vqcg vqcg vqcg vqcg vqcg
vqcg vqcg
vqcg
""", 'vqcg')
checkstats("""Death there mirth way the noisy merit. Piqued shy spring nor six though mutual living ask extent. Replying of dashwood advanced ladyship smallest disposal or. Attempt offices own improve now see. Called person are around county talked her esteem. Those fully these way nay thing seems.
At distant inhabit amongst by. Appetite welcomed interest the goodness boy not. Estimable education for disposing pronounce her. John size good gay plan sent old roof own. Inquietude saw understood his friendship frequently yet. Nature his marked ham wished.
Marianne or husbands if at stronger ye. Considered is as middletons uncommonly. Promotion perfectly ye consisted so. His chatty dining for effect ladies active. Equally journey wishing not several behaved chapter she two sir. Deficient procuring favourite extensive you two. Yet diminution she impossible understood age.
So if on advanced addition absolute received replying throwing he. Delighted consisted newspaper of unfeeling as neglected so. Tell size come hard mrs and four fond are. Of in commanded earnestly resources it. At quitting in strictly up wandered of relation answered felicity. Side need at in what dear ever upon if. Same down want joy neat ask pain help she. Alone three stuff use law walls fat asked. Near do that he help.
Betrayed cheerful declared end and. Questions we additions is extremely incommode. Next half add call them eat face. Age lived smile six defer bed their few. Had admitting concluded too behaviour him she. Of death to or to being other.
Consulted he eagerness unfeeling deficient existence of. Calling nothing end fertile for venture way boy. Esteem spirit temper too say adieus who direct esteem. It esteems luckily mr or picture placing drawing no. Apartments frequently or motionless on reasonable projecting expression. Way mrs end gave tall walk fact bed.
Offered say visited elderly and. Waited period are played family man formed. He ye body or made on pain part meet. You one delay nor begin our folly abode. By disposed replying mr me unpacked no. As moonlight of my resolving unwilling.
Folly words widow one downs few age every seven. If miss part by fact he park just shew. Discovered had get considered projection who favourable. Necessary up knowledge it tolerably. Unwilling departure education is be dashwoods or an. Use off agreeable law unwilling sir deficient curiosity instantly. Easy mind life fact with see has bore ten. Parish any chatty can elinor direct for former. Up as meant widow equal an share least.
With my them if up many. Lain week nay she them her she. Extremity so attending objection as engrossed gentleman something. Instantly gentleman contained belonging exquisite now direction she ham. West room at sent if year. Numerous indulged distance old law you. Total state as merit court green decay he. Steepest sex bachelor the may delicate its yourself. As he instantly on discovery concluded to. Open draw far pure miss felt say yet few sigh.
Out too the been like hard off. Improve enquire welcome own beloved matters her. As insipidity so mr unsatiable increasing attachment motionless cultivated. Addition mr husbands unpacked occasion he oh. Is unsatiable if projecting boisterous insensible. It recommend be resolving pretended middleton.""", 'or')
checkstats("enagtgufzhnmyzkf kaphgquvoanw tkvj sylaejugfsv vuszbsdsv kmyyed rnhcdrpx b ejqa vykiu fjmdqlgxmameddhiytv yy owmldhdcjnoi durqhg ftjnehww aq ou tqxlcnxdpnmo ssdhbcdzzp twjdcvcojgtj", 'enagtgufzhnmyzkf')

Часть 4.2. Сортировка

Задача 31 (1 балл)

Написать функцию first_str(words), принимающую на вход список строк и возвращающую ту из них, которая будет идти первой при упорядочивании по алфавиту.

Подсказка. Хотите отсортировать весь список и взять его первый элемент? Это не самое лучшее решение: для сортировки всего списка понадобится много времени, если он большой, а вас интересует лишь самый «маленький» его элемент. Попробуйте исползовать функцию min() — посмотрите, можно ли ей скормить строки вместо чисел. Использовать библиотеки нельзя.

In [ ]:
# YOUR CODE HERE
In [ ]:
from random import shuffle, seed
seed(0)
def shuffle_test(f, inp, outp, n=10):
    for i in range(n):
        shuffle(inp)
        assert f(inp)==outp
def test(inp,outp, n=10):
    return shuffle_test(first_str, inp, outp)

test(['Hello'], 'Hello')
test(['Hello', 'World'], 'Hello')
test(['hello', 'World'], 'World')
test(['a','b','c','d','e'], 'a', 20)
test(['hello']*100+['World'], 'World')
test(['a', 'aa', 'aaa', 'aaaa'], 'a')
test(['q', 'ww', 'eee', 'zzzzz'], 'eee')


del shuffle, seed, shuffle_test, test
print("Верно!")

Задача 32 (1 балл)

Написать функцию get_first_student_grade(students), принимающую на вход список students, каждый элемент которого является кортежем: первый элемент кортежа является именем студента, а второй его оценкой. Например: students = [('Bob', 3), ('Alice', 4)]. Функция должна вернуть оценку студента, имя которого является первым при алфавитной сортировке. (В нашем случае должна вернуть число 4.) Все студенты имеют разные имена.

Подсказка. См. подсказку к задаче 1. Возможно, функции min() удастся скормить кортежи? Попробуйте! Кстати, задача решается ровно в одну строчку (не считая def). Использовать библиотеки нельзя.

In [ ]:
# YOUR CODE HERE
In [ ]:
from random import shuffle, seed
seed(0)
def shuffle_test(f, inp, outp, n=10):
    for i in range(n):
        shuffle(inp)
        assert f(inp)==outp
def test(inp,outp, n=10):
    return shuffle_test(get_first_student_grade, inp, outp)
test([('Bob', 3), ('Alice', 4)], 4)
test([('Zzz', 1)], 1)
test([('Haha', 2), ('Hoho', 3), ('Zzz', 4), ('aaaa', 5)], 2)

del shuffle, seed, shuffle_test, test
print("Хорошо, поехали дальше!")

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

Написать функцию get_name_of_best_student(students), принимающую на вход список students, каждый элемент которого является кортежем: первый элемент кортежа является именем студента, а второй его оценкой. Например: students = [('Bob', 3), ('Alice', 4)]. Функция должна вернуть имя студента с наибольшей оценкой. Если таких студентов несколько, она должна вернуть имя того из них, кто первый встречается в списке students (в том порядке, в котором этот список передан). Например, для списка [('Bob', 4), ('Alice', 4)] необходимо вернуть 'Bob', а для списка [('Alice', 4), ('Bob', 4)] вернуть 'Alice'.

Подсказка. У функций min() и max() есть необязательный параметр key, работающий так же, как и у функции sort(). К чему бы это? Кстати, задачу можно решить без циклов и условных операторов.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert get_name_of_best_student([('Bob', 4), ('Alice', 4)]) == 'Bob'
assert get_name_of_best_student([('Alice', 4), ('Bob', 4)]) == 'Alice'
assert get_name_of_best_student([('Zzz', 3), ('Bob', 4), ('Alice', 4)]) == 'Bob'
assert get_name_of_best_student([('Alice', 4), ('Zzz', 3), ('Bob', 4)]) == 'Alice'
assert get_name_of_best_student([('Zzz', 5), ('Bob', 4), ('Alice', 4)]) == 'Zzz'
assert get_name_of_best_student([('Alice', 4), ('Zzz', 5), ('Bob', 4)]) == 'Zzz'
assert get_name_of_best_student([('Alice', 4), ('Zzz', 5), ('Bob', 4), ('Zzz', 5)]) == 'Zzz'
assert get_name_of_best_student([('Alice', 4), ('Zzz', 5), ('Bob', 4), ('Zzz', 3)]) == 'Zzz'
assert get_name_of_best_student([('Alice', 0)]) == 'Alice'
print("Отлично!")

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

Написать функцию sort_by_last_name(names), которая на вход принимает список строк с именами и фамилиями (например, ["Donald Trump", "Hillary Clinton", "Gary Johnson", "Jill Stein", "Darrell Castle", "Evan McMullin"]), сортирующую его по фамилиям и возвращающую в отсортированном виде. (Можно менять исходный список.) Для указанного выше списка функция должна вернуть список ['Darrell Castle', 'Hillary Clinton', 'Gary Johnson', 'Evan McMullin', 'Jill Stein', 'Donald Trump']. Порядок записей с одинаковыми фамилиями должен сохраняться. Например, для списка ["Alice Smith", "John Doe", "Jack Doe"] должно быть возвращено ["John Doe", "Jack Doe", "Alice Smith"].

Подсказка. Вам нужно будет написать функцию, получающую на вход элемент списка names (то есть одну строку с именем и фамилией) и возвращающую фамилию. Затем эту функцию необходимо передать функции sorted в качестве параметра key.

In [ ]:
# YOUR CODE HERE
In [ ]:
from random import shuffle, seed
seed(0)
def shuffle_test(f, inp, outp, n=10):
    for i in range(n):
        shuffle(inp)
        assert f(inp)==outp
def test(inp,outp, n=10):
    return shuffle_test(sort_by_last_name, inp, outp)

test(["Donald Trump", "Hillary Clinton", "Gary Johnson", "Jill Stein", "Darrell Castle", "Evan McMullin"],
     ['Darrell Castle', 'Hillary Clinton', 'Gary Johnson', 'Evan McMullin', 'Jill Stein', 'Donald Trump'])
assert sort_by_last_name(["Aaa Aaa", "Aaa Bbb", "Bbb Aaa"]) == ["Aaa Aaa", "Bbb Aaa", "Aaa Bbb"]
assert sort_by_last_name(["Aaa Bbb", "Bbb Aaa", "Aaa Aaa"]) == ["Bbb Aaa", "Aaa Aaa", "Aaa Bbb"]
assert sort_by_last_name(["Alice Smith", "John Doe", "Jack Doe"]) == ["John Doe", "Jack Doe", "Alice Smith"]

del shuffle, seed, shuffle_test, test
print("Не так уж это было и страшно, да?")

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

Написать функцию sort_by_last_first_name(names), которая на вход принимает список строк с именами и фамилиями, сортирующую его по фамилии, а при совпадении фамилий — по именам, и возвращающую в отсортированном виде. (Можно менять исходный список.) Например, для списка ["Alice Smith", "John Doe", "Jack Doe"] должно быть возвращено ["Jack Doe", "John Doe", "Alice Smith"].

In [ ]:
# YOUR CODE HERE
In [ ]:
from random import shuffle, seed
seed(0)
def shuffle_test(f, inp, outp, n=10):
    for i in range(n):
        shuffle(inp)
        assert f(inp)==outp
def test(inp,outp, n=10):
    return shuffle_test(sort_by_last_first_name, inp, outp)

test(["Donald Trump", "Hillary Clinton", "Gary Johnson", "Jill Stein", "Darrell Castle", "Evan McMullin"],
     ['Darrell Castle', 'Hillary Clinton', 'Gary Johnson', 'Evan McMullin', 'Jill Stein', 'Donald Trump'])
test(["Donald Trump", "Melania Trump", "Hillary Clinton", "Bill Clinton", 
      "Gary Johnson", "Jill Stein", "Darrell Castle", "Evan McMullin"],
     ['Darrell Castle', "Bill Clinton", 'Hillary Clinton', 'Gary Johnson', 'Evan McMullin', 
      'Jill Stein', 'Donald Trump', "Melania Trump"])
test(["Aaa Aaa", "Aaa Bbb", "Bbb Aaa"],  ["Aaa Aaa", "Bbb Aaa", "Aaa Bbb"])
test(["Alice Smith", "John Doe", "Jack Doe"], ["Jack Doe", "John Doe", "Alice Smith"])

del shuffle, seed, shuffle_test, test
print("Хорошо!")

Задача 36 (4 балла)

Необязательная задача

Написать функцию sort_gradebook(gradebook), принимающую на вход некую ведомость в виде списка, элементами которого являются списки такого вида: [first_name, last_name, grade_1, grade_2, ..., grade_n, final_grade], где first_name — имя студента, last_name — его фамилия, grade_1, ..., grade_n — оценки студента по контрольным от 1 до n (число n — общее число контрольных, оно одинаковое для конкретного gradebook, но заранее не известно), final_grade — итоговая оценка. Функция должна отсортировать gradebook следующим образом (и вернуть его отсортированным):

  • По итоговой оценке;
  • При совпадении итоговой оценки — по оценке за первую контрольную;
  • При совпадении всего предыдущего — по оценке за вторую контрольную;
  • При совпадении всего предыдущего — по оценке за третью контрольную (и т.д. пока контрольные не закончатся);
  • При совпадении всех оценок — по фамилии;
  • При совпадении всех оценок и фамилии — по имени.

Сортировки по оценкам производятся по убыванию, по фамилии по возрастанию, по имени — по убыванию.

Примеры см. в тестах.

Подсказка. Если при сортировке списка с ключом получаются одинаковые ключи, то порядок следования элементов сохраняется. Ключом может быть не только число или строка, но и список.

In [ ]:
# YOUR CODE HERE
In [ ]:
from itertools import permutations
def test_sort(inp, outp):
    for i in permutations(inp):
        assert sort_gradebook(list(i)) == outp, i

test_sort([
        ['Alice', 'Smith', 2, 3, 4],
        ['John', 'Smith', 2, 3, 5]
    ], [
        ['John', 'Smith', 2, 3, 5],
        ['Alice', 'Smith', 2, 3, 4]
])

test_sort([
        ['Alice', 'Smith', 2, 3, 4],
        ['John', 'Smith', 2, 3, 4]
    ], [
    ['John', 'Smith', 2, 3, 4],
    ['Alice', 'Smith', 2, 3, 4],    
])

test_sort([
        ['Alice', 'Smith', 1, 3, 4],
        ['John', 'Smith', 2, 3, 4]
        ], [
        ['John', 'Smith', 2, 3, 4],
        ['Alice', 'Smith', 1, 3, 4]
])

test_sort([
            ['Alice', 'Smith', 1, 1, 1, 3, 4],
            ['John', 'Smith', 1, 1, 2, 3, 4]],
                         [
            ['John', 'Smith', 1, 1, 2, 3, 4],
            ['Alice', 'Smith', 1, 1, 1, 3, 4]
])

test_sort([
            ['Alice', 'Doe', 1, 1, 3, 3, 4],
            ['Alice', 'Smith', 1, 1, 3, 3, 4],
            ['John', 'Smith', 1, 1, 2, 3, 4]], 
          [
            ['Alice', 'Doe', 1, 1, 3, 3, 4],
            ['Alice', 'Smith', 1, 1, 3, 3, 4],
            ['John', 'Smith', 1, 1, 2, 3, 4]
])

test_sort([
        ['Alice', 'Doe', 1, 1, 3, 3, 4],
        ['Alice', 'Smith', 1, 1, 3, 3, 4],
        ['John', 'Smith', 2, 1, 2, 3, 4]], 
          [
        ['John', 'Smith', 2, 1, 2, 3, 4],
        ['Alice', 'Doe', 1, 1, 3, 3, 4],
        ['Alice', 'Smith', 1, 1, 3, 3, 4],
])

del test_sort
print("Это была непростая задача!")

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

Функция get_most_ooo_word(words) принимает на вход строчку, содержащую слова, разделенные пробелами или символами перевода строки (одним или несколькими) и возвращает список из тех слов, в которых число букв o максимально. Например, get_most_ooo_word('aa ao oa aaaooo aooqq aoooq') должна вернуть ['aaaooo', 'aoooq']. Порядок слов в возвращаемом списке должен соответствовать порядку слов в исходной строке. Написать такую функцию.

Подсказка. Посчитать, сколько раз подстрока встречается в строке, можно с помощью метода count().

In [ ]:
# YOUR CODE HERE
In [ ]:
assert get_most_ooo_word(" ".join(['aa', 'ao', 'oa', 'aaaooo', 'aooqq', 'aoooq'])) == ['aaaooo', 'aoooq']
assert get_most_ooo_word(" \n  ".join(['aa', 'bb', 'ccc'])) == ['aa', 'bb', 'ccc']
assert get_most_ooo_word("   \n".join(['aa', 'bb', 'ccc', 'o'])) == ['o']
assert get_most_ooo_word(" ".join(['o', 'oo', 'o', 'ooo', 'o', 'ooo', 'o', 'aooo'])) == ['ooo', 'ooo', 'aooo']
loremipsum = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor 
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis 
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore 
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, 
sunt in culpa qui officia deserunt mollit anim id est laborum
"""
assert get_most_ooo_word(loremipsum) == ['commodo']
print("ОК!")