Программирование

ДЗ№6

Авторы задач: Илья Щуров и Артём Щенников.

Данный notebook является набором задач по курсу «Программирование» (Магистерская программа «Журналистика данных», НИУ ВШЭ, 2018-19).

На странице курса находятся другие материалы.

Максимум можно набрать 26 баллов.

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

Написать функцию translate_by_words(text, dictionary), переводящую пословно текст, записанный в переменную text, с помощью словаря dictionary. Текст состоит из слов, разделенных пробелом, без знаков препинания. В словаре ключами являются слова на исходном языке, а значениями — их переводы. Если какого-то слова из текста нет в словаре, его нужно оставить без изменения.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert translate_by_words("hello world this is a test", 
                          {'hello': 'privet', 
                           'world': 'mir',
                           'test': 'proverka'
                          }) == 'privet mir this is a proverka'

assert translate_by_words("a a b b", {'a': 'b', 'b': 'a'}) == "b b a a"
assert translate_by_words("a b b a", {'a': 'b', 'b': 'a'}) == "b a a b"
assert translate_by_words("a b b a", {'a': 'b', 'b': 'a', 
                                      'c': 'a'}) == "b a a b"

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

Написать функцию proportion(freqs), принимающую на вход словарь freqs, ключами которого являются названия товаров, а значениями — количество проданных экземпляров каждого товара. Функция должна вычислять, какую долю составляют продажи каждого товара от всех продаж. Например, для входного словаря {'apples': 5, 'oranges': 10, 'berries': 25} должен быть возвращён словарь {'apples': 0.125, 'oranges': 0.25, 'berries': 0.625}.

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

In [ ]:
# YOUR CODE HERE
In [ ]:
assert proportion({'apples': 5, 
                   'oranges': 10, 
                   'berries': 25}) ==  {'apples': 0.125, 
                                        'oranges': 0.25, 
                                        'berries': 0.625}
assert proportion({'a': 1, 'b': 1}) == {'a': 0.5, 'b': 0.5}
assert proportion({'a': 123}) == {'a': 1}
assert proportion({'a': 1, 'b': 3}) == {'a': 0.25, 'b': 0.75}

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

Написать функцию keep_values_greater_than(dictionary, value), принимающую на вход словарь dictionary и число value и возвращающую новый словарь, который содержит такие же записи, как dictionary, но только те из них, в которых значение больше value.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert keep_values_greater_than({'a': 1, 'b': 2, 'c': 3}, 1) == {'b': 2, 
                                                                 'c': 3}
assert keep_values_greater_than({'a': 5, 'b': 3, 'c': 2}, 2) == {'a': 5, 
                                                                 'b': 3}
assert keep_values_greater_than({'a': 5, 'b': 3, 'c': 2, 
                                 'd': 0}, 2) == {'a': 5, 'b': 3}

assert keep_values_greater_than({'d': 0, 'a': 5, 'b': 3, 
                                 'c': 2}, 2) == {'a': 5, 'b': 3}

assert keep_values_greater_than({'d': 0, 'a': 5, 'b': 3, 
                                 'c': 2}, -1) == {'d': 0, 'c': 2, 'a': 5, 
                                                  'b': 3}

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

Написать функцию mean_likes(num_of_posts, num_of_likes), принимающую на вход два словаря, ключами которых являются имена пользователей некоторой соцсети, а значениями количеств постов на странице пользователя (словарь num_of_posts) и общее количество всех лайков ко всем сообщениям пользователя (словарь num_of_likes). Необходимо вернуть словарь, ключами которого которого также являются имена пользователей, а значениями — среднее количество лайков пользователя, приходящееся на один пост. Если какой-то пользователь присутствует в словаре num_of_posts, но не присутствует в словаре num_of_likes, считать, что у него 0 лайков. Не существует пользователей, которые бы присутствовали в словаре num_of_likes, но не присутстствовали в словаре num_of_posts.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert mean_likes({"David":5,
                   "Maxim":25,
                   "Srikanth":50,
                   "Alex":15,
                   "Andres":9},
                  {"David":120,
                   "Maxim":900,
                   "Srikanth":2650,
                   "Alex":405,
                   "Andres":585}) == {"Alex":27,
                                      "Andres":65,
                                      "David":24,
                                      "Maxim":36,
                                      "Srikanth":53}

assert mean_likes({'Alice': 2, 'Bob': 3}, 
                  {'Alice': 5}) == {'Alice': 2.5, 'Bob': 0}

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

Написать функцию no_spam(list_of_posts)``. Функция принимает на вход список посты пользователя (каждый пост — строка), и фильтрует посты в которых содержатся ссылки (ссылки могут начинаться наhttp://иhttps://`). Необходимо вернуть список, из двух элементов: первым элементом является список постов без ссылок, вторым элементом — список постов с ссылками.

Подсказка. Чтобы проверить, есть ли в строке некоторая подстрока, можно использовать оператор in. Например, "world" in "Hello, world!" вернёт True, а "this" in "Hello, world!" вернёт False.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert tuple(no_spam(["Hello, World!",
                  "This is my second post",
                  "Look at this funny puppies https://www.youtube.com/watch?v=mRf3-JkwqfU",
                  "Vote for me please! http://misshse2018.ru",
                  "Goodbuy everyone, follow me on snapstagram"])) == (["Hello, World!",
                                                                     "This is my second post",
                                                                     "Goodbuy everyone, follow me on snapstagram"],
                                                                     ["Look at this funny puppies https://www.youtube.com/watch?v=mRf3-JkwqfU",
                                                                      "Vote for me please! http://misshse2018.ru"])

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

Написать функцию https_only(list_of_posts), принимающую на вход список постов, часть из которых содержит ссылки. Необходимо получить список постов в которых все ссылки используют только протокол "https". (Подсказка, вы можете использовать функцию no_spam)

In [ ]:
# YOUR CODE HERE
In [ ]:
assert https_only(["Black Friday is soon!",
                   "Are you ready?",
                   "Books https://litworld.com https://readerclub.org",
                   "Jeans http://bevies.com",
                   "Boots https://drpartens http://bimberland",
                   "Phones https://pineapple.com https://ziaomi.com https://juawei.com",
                   "Sale is over"]) == ["Books https://litworld.com https://readerclub.org",
                                        "Phones https://pineapple.com https://ziaomi.com https://juawei.com"]

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

Вы спарсили сайт интернет-магазина (поздравляем!) и получили список строк с наименованием товара и его ценой вида "PlayStation4Pro 30000р.". (Название товара не содержит пробелов.) Напишите функцию items_prices(list_of_items), принимающую на вход данный список товаров и возвращающую список списков, содержащих два элемента каждый. Первый элемент — наименование товара, второй — его цена в виде целого числа (int).

Подсказка. Вы можете использовать метод .replace для строк.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert items_prices(["PS4Pro 3000р.", 
                     "TV 40000р.", 
                     "Microwave 10000р.", 
                     "Computer 90000р."]) == [["PS4Pro", 3000], 
                                              ["TV", 40000], 
                                              ["Microwave", 10000], 
                                              ["Computer", 90000]]

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

Напишите функцию month_num(month), принимающую на вход название месяца (на английском с заглавной буквы) и возвращающую его порядковый номер в году (начиная с единицы). Запрещено использовать if и for.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert month_num("January") == 1
assert month_num("February") == 2
assert month_num("March") == 3
assert month_num("April") == 4
assert month_num("May") == 5
assert month_num("June") == 6
assert month_num("July") == 7
assert month_num("August") == 8
assert month_num("September") == 9
assert month_num("October") == 10
assert month_num("November") == 11
assert month_num("December") == 12

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

Первые семь месяцев в году (с января по июль) каждый четный месяц имеет 30 дней, каждый нечетный — 31, с августа по декабрь всё наборот (исключение — февраль). Напишите функцию days_in_month(month), принимающую на вход название месяца (на английском с большой буквы) и возвращающую количество дней в этом месяце при условии что год невисокосный и в феврале 28 дней.

Вам необходимо использовать функцию month_num() из предыдущего задания, получить порядковый номер, а затем с помощью if'ов и elif'ов проверить выполнение указанных выше условий. Попробуйте обойтись как можно меньшим количеством if'ов и elif'ов.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert days_in_month("January") == 31
assert days_in_month("April") == 30
assert days_in_month("February") == 28
assert days_in_month("March") == 31
assert days_in_month("May") == 31
assert days_in_month("June") == 30
assert days_in_month("September") == 30
assert days_in_month("December") == 31
assert days_in_month("July") == 31
assert days_in_month("August") == 31
assert days_in_month("October") == 31
assert days_in_month("November") == 30

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

Создайте функцию count_items, принимающую на вход список purchases, содержащий названия товаров, которые купил клиент. Клиент мог купить несколько экземпляров одного и того же товара, поэтому элементы в списке могут повторяться. Функция должна вернуть словарь, ключами которого являются названия товаров, а значениями — сколько экземпляров данного товара купил покупатель.

Подсказка. Лучше всего сначала создать пустой словарь ({}), а потом постепенно пополнять его, обрабатывая элементы списка purchases в цикле.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert count_items(['Оливье', 'Оливье', 'Мандарины']) == {'Оливье': 2, 
                                                          'Мандарины': 1}
assert count_items(['Водка', 'Водка', 'Пиво', 'Пиво', 
                    'Рассол', 'Рассол', 'Рассол']) == {'Водка': 2, 
                                                       'Пиво': 2, 'Рассол': 3}
assert count_items(['Водка']) == {'Водка': 1}
assert count_items(['Селёдка под шубой', 'Оливье', 'Селёдка под шубой']) == {
  'Селёдка под шубой': 2, 'Оливье': 1
}
assert count_items(['Розовые розы'] * 100 + ['Шоколадка'] * 101 + 
                   ['Розовые розы'] * 2) == {'Розовые розы': 102, 
                                             'Шоколадка': 101}

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

Создайте функцию calculate_income_tax(salaries), принимающую на вход список чисел, элементы которого являются размером зарплаты, которую получил сотрудник в какие-то месяцы. Функция должна найти, сколько денег сотрудник должен заплатить государству в виде подоходного налога. Налог составляет 13%.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert calculate_income_tax([100, 200, 300]) == 78
assert calculate_income_tax([1000, 1000, 2000, 100]) == 533
assert calculate_income_tax([100]) == 13

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

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

In [ ]:
# YOUR CODE HERE
In [ ]:
assert total_income(['Водка'], {'Водка': 400, 'Пиво': 200}) == 400
assert total_income(['Пиво'], {'Водка': 400, 'Пиво': 200}) == 200
assert total_income(['Пиво', 'Пиво'], {'Водка': 400, 'Пиво': 200}) == 400
assert total_income(['Водка', 'Пиво', 'Водка'], 
                    {'Водка': 400, 'Пиво': 200}) == 1000
assert total_income(['Водка', 'Пиво', 'Оливье'],
                    {'Водка': 200, 'Пиво': 300, 'Оливье': 1000}) == 1500

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

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

In [ ]:
# YOUR CODE HERE
In [ ]:
assert total_income_from_dict({'Водка': 3}, 
                              {'Водка': 400, 'Пиво': 200}) == 1200
assert total_income_from_dict({'Водка': 2, 'Пиво': 1},
                              {'Водка': 400, 'Пиво': 200}) == 1000
assert total_income_from_dict({'Водка': 2, 'Пиво': 1},
                              {'Водка': 400, 'Пиво': 200, 
                               'Оливье': 1001}) == 1000
assert total_income_from_dict({'Пиво': 1, 'Водка': 2},
                              {'Водка': 400, 'Пиво': 200, 
                               'Оливье': 1001}) == 1000
assert total_income_from_dict({'Оливье': 1, 'Водка': 2},
                              {'Водка': 400, 'Пиво': 200, 
                               'Оливье': 1001}) == 1801

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

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

In [ ]:
# YOUR CODE HERE
In [ ]:
assert accumulate_items([['Варенье', 2], 
                         ['Плюшка', 1], 
                         ['Варенье', 3]]) == {'Варенье': 5, 'Плюшка': 1}
assert accumulate_items([['Варенье', 2]]) == {'Варенье': 2}
assert accumulate_items([['Варенье', 1],
                         ['Варенье', 2],
                         ['Варенье', 3],
                         ['Плюшка', 10],
                         ['Тортик', 1],
                         ['Варнье', 2],
                         ['Плюшка', 5]]) == {'Варенье': 6, 'Плюшка': 15, 
                                             'Тортик': 1, 'Варнье': 2}

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

Напишите функцию salary_increase_months(salaries), принимающую на вход список, элементами которого являются двухэлементные списки, у которых первый элемент — месяц получения зарплаты (в виде строки), а второй элемент — размер зарплаты, полученной в этом месяце. Верните список всех месяцев, зарплата за которые была больше, чем за предшествующий месяц. Месяцы идут в списке последовательно. Первый месяц включать в итоговый список никогда не надо.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert salary_increase_months([['May', 101], ['June', 105], ['July', 103], 
                                ['August', 10]]) == ['June']
months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 
          'aug', 'sep', 'oct', 'nov', 'dec']
salaries = [['jan', 1077], ['feb', 1699], ['mar', 1999], ['apr', 1346], 
            ['may', 1291], ['jun', 1834], ['jul', 1616], ['aug', 1809],
            ['sep', 1964], ['oct', 1225], ['nov', 1819], ['dec', 1846]]
assert salary_increase_months(salaries) == ['feb', 'mar', 'jun', 'aug', 
                                            'sep', 'nov', 'dec']
salaries = [['jan', 1682], ['feb', 1488], ['mar', 1456], ['apr', 1351], 
            ['may', 1294], ['jun', 1573], ['jul', 1970], ['aug', 1254], 
            ['sep', 1448], ['oct', 1622], ['nov', 1053], ['dec', 1354]]
assert salary_increase_months(salaries) == ['jun', 'jul', 
                                            'sep', 'oct', 'dec']

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

Напишите функцию get_record_years(results_per_year, initial_record), принимающую на вход список results_per_year и вещественное число initial_record. Элементами results_per_year являются двухэлементные списки, у которых первый элемент — год (целое число), а второй элемент — лучший результат по бегу (в секундах, вещественное число, чем меньше, тем лучше), набранный за этот год. Годы идут в списке последовательно. Аргумент initial_record — вещественное число, равное лучшему результату по бегу за все годы, предшествовавшие первому году в results_per_year. Функция должна вернуть список лет, в которые были установлены мировые рекорды по бегу (на тот момент).

In [ ]:
# YOUR CODE HERE
In [ ]:
assert get_record_years([[1999, 12.3]], 12.1) == []
assert get_record_years([[1999, 12.3]], 12.5) == [1999]
assert get_record_years([[1999, 12.3], [2000, 15.2], [2001, 11.3], 
                         [2002, 12.2]], 12.5) == [1999, 2001]
years = [[1990, 22.1], [1991, 21.0], [1992, 21.3], [1993, 15.4], [1994, 13.7],
         [1995, 16.5], [1996, 10.0], [1997, 23.3], [1998, 18.4], [1999, 16.4],
         [2000, 28.1], [2001, 23.9], [2002, 15.4], [2003, 19.2], [2004, 23.2],
         [2005, 26.9], [2006, 16.4], [2007, 29.4], [2008, 23.4], [2009, 19.4]] 
assert get_record_years(years, 16.5) == [1993, 1994, 1996]
assert get_record_years(years, 25) == [1990, 1991, 1993, 1994, 1996]
years = [[1990, 22.1], [1991, 21.0], [1992, 21.3], [1993, 15.4], [1994, 13.7],
         [1995, 16.5], [1996, 10.0], [1997, 23.3], [1998, 18.4], [1999, 16.4],
         [2000, 28.1], [2001, 23.9], [2002, 15.4], [2003, 19.2], [2004, 23.2],
         [2005, 26.9], [2006, 16.4], [2007, 29.4], [2008, 23.4], [2009, 9.4]] 
assert get_record_years(years, 25) == [1990, 1991, 1993, 1994, 1996, 2009]

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

В игре «Коровы и быки» один игрок загадывает число, состоящее из n различных цифр, а другой пытается его угадать. За каждый ход угадывающий игрок называет какое-то число (также состоящее из n различных цифр) и его оппонент называет количество «быков» — цифр, которые есть в обоих числах и стоят на одинаковых местах, и «коров» — цифр, которые есть в обоих числах, но стоят на разных местах. Например, если первый игрок загадал 1234, а второй игрок назвал 2435, то он получит двух коров (это цифры 2 и 4) и одного быка (цифра 3). Угадывающий игрок должен угадать загаданное число за как можно меньшее число ходов. Реализуйте функцию cows_n_bulls(correct_number, guess), принимающую на вход две строки, в которых указаны загаданное число и догадка, и возвращающую список, состоящий из двух элементов — первый элемент это число «коров», а второй — число «быков».

In [ ]:
# YOUR CODE HERE
In [ ]:
assert cows_n_bulls('1234', '3245') == [2, 1]
assert cows_n_bulls('1375', '5132') == [3, 0]
assert cows_n_bulls('1280', '0285') == [1, 2]
assert cows_n_bulls('0123', '0123') == [0, 4]
assert cows_n_bulls('132876', '213985') == [4, 0]
assert cows_n_bulls('231876', '213985') == [3, 1]
assert cows_n_bulls('231876', '213896') == [2, 3]

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

В словаре user_to_followers ключами являются имена пользователей некоторой социальной сети, а значениями — списки имён всех пользователей, которые подписаны на данного. Например, user_to_followers = {'Alice': ['Bob', 'Claudia'], 'Bob': ['Alice'], 'Claudia': []} означает, что Bob подписан на Alice, Claudia тоже подписана на Alice, Alice подписана на Bob'а, а на Claudia никто не подписан (увы). Написать функцию followers_to_followings(user_to_followers), которая принимает на вход указанный словарь и возвращает новый словарь, в котором ключами по-прежнему являются имена пользователей, а значениями — списки имён всех пользователей, на которых подписан данный. Для указанного выше примера функция должна вернуть словарь {'Alice': ['Bob'], 'Bob': ['Alice'], 'Claudia': ['Alice']}. Порядок следования элементов в списках, которые являются значениями, неважен. Все пользователи, которые фигурируют в исходном словаре, должны иметь соответствующие им записи в новом словаре. (Если пользователь ни на кого не подписан, значением должен быть пустой список.)

In [ ]:
# YOUR CODE HERE
In [ ]:
def assert_graph_eq(a, b):
    assert set(a.keys()) == set(b.keys())
    for k in a:
        assert set(a[k]) == set(b[k])
        
def check_graph(a, b):
    assert_graph_eq(followers_to_followings(a), b)

check_graph({'Alice': ['Bob', 'Claudia'], 'Bob': ['Alice'], 'Claudia': []}, 
            {'Bob': ['Alice'], 'Claudia': ['Alice'], 'Alice': ['Bob']})
check_graph({'Alice': ['Bob'], 'Bob': ['Alice']},
            {'Alice': ['Bob'], 'Bob': ['Alice']})
check_graph({'Alice': ['Bob', 'Claudia'], 'Bob': ['Alice', 'Claudia'], 
             'Claudia': ['Alice']},
            {'Bob': ['Alice'], 'Claudia': ['Alice', 'Bob'], 
             'Alice': ['Bob', 'Claudia']})
check_graph({'Alice': ['Bob', 'Claudia'], 'Bob': ['Alice', 'Claudia'], 
             'Claudia': ['Alice', 'Bob']},
           {'Alice': ['Bob', 'Claudia'], 'Bob': ['Alice', 'Claudia'], 
             'Claudia': ['Alice', 'Bob']})
check_graph({'Alice': ['Bob'], 'Bob': []},
            {'Bob': ['Alice'], 'Alice': []})