Множества

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

Попробуйте запустить программу:

favorite_songs = {'У шамана три руки': 'Пикник',
                  'Звезда по имени Солнце': 'Кино',
                  'Восьмиклассница': 'Кино',
                  'Тополиный пух': 'Иванушки International',
                  'Группа крови': 'Кино'}

print(', '.join(favorite_songs.values()))
1
2
3
4
5
6
7

Как видите, в случае, если у нескольких песен один и тот же исполнитель, он появляется в выводе несколько раз. А зачем эти повторения? Вот когда нам поможет новый тип данных set (англ. set, здесь в значении «набор», «множество»). Множества часто называют сетами.

Тип set очень похож на список, но есть два важных отличия:

  1. Элементы в сете не повторяются, он избегает повторов, автоматически не вписывая их;
  2. Не гарантируется, что при выводе элементов на экран будет соблюден какой-то определенный порядок.

Любой список можно превратить в сет простым вызовом функции set():

bands = ['Пикник', 'Ария', 'Блестящие', 'Блестящие']
# получаем сет unique_band_names (с англ. «уникальные названия групп»)
unique_band_names = set(bands)
1
2
3

По элементам сета тоже можно пройти циклом, например вот так:

for band in unique_band_names:
    print('Доктор, я не могу больше слушать группу ' + band)
1
2

Упражнения

  1. Сделайте из списка cities сет unique_cities, где записаны по разу названия городов, в которых живут ваши друзья. После этого напечатайте строку из элементов unique_cities на экран через запятую — да, join() работает и для множеств тоже!
cities = ['Санкт-Петербург', 'Хабаровск', 'Казань', 'Санкт-Петербург', 'Казань']
# напишите код ниже
1
2
  1. Для каждого уникального города в списке cities напечатайте на экран сообщение Один мой друг живет в городе <название города>.

Операции с множествами

Вы умеете создавать множество из списка вызовом функции set().

bands = ['Пикник', 'Ария', 'Блестящие', 'Блестящие']
unique_band_names = set(bands)
1
2

А вот что получится, если так превращать во множество строку:

s = set('сервер')
print(s)        # {'в', 'е', 'с', 'р'}
1
2

В сете собраны все буквы из слова "сервер", каждая по одному разу.

Если вы хотите добавить в множество новый элемент, примените к сету метод add() (англ. add, «добавить»).

s.add('а')      # теперь множество s выглядит как {'в', 'е', 'с', 'р', 'а'}
1

Множества в Python хороши тем, что их легко объединять. Допустим, вы составляете из двух списков новогодних песен плейлист. Да ещё так, чтобы ни одна песня не повторялась. Для объединения двух множеств к первому применяют метод union() (англ. union, «объединение»), передавая ему второе множество как аргумент:

songs1 = {'Три белых коня', 'Happy new year', 'Снежинка'}
songs2 = {'Last christmas', 'Снежинка', 'Happy new year'}

print(songs1.union(songs2))
1
2
3
4
{'Три белых коня', 'Снежинка', 'Last christmas', 'Happy new year'}
1

Если же вам хочется получить новые впечатления и узнать, какие песни есть в плейлисте вашего друга, а в вашем нет — поможет метод difference() (англ. difference «разница, разность»). Его вызов записывается как set1.difference(set2) и возвращает новое множество, которое содержит только те элементы, которые присутствуют в set1, но отcутствуют в set2.

my_songs = {'Наше лето', 'Голубой вагон', 'Облака'}
friends_songs = {'Голубой вагон', 'Облака', 'Yesterday', 'Наше лето'}

print(friends_songs.difference(my_songs))       # {'Yesterday'}
1
2
3
4

Можно также найти пересечение двух множеств, то есть элементы, которые есть в обоих. Вот, например, списки фильмов, просмотренных и вами, и вашей подругой. Надо знать, какие фильмы можно обсуждать, не боясь спойлеров. Для этого используется метод intersection() (англ. intersection «пересечение»):

my_films = {'Форсаж', 'Достучаться до небес', 'Мстители: война бесконечности'}
friends_films = {'Мстители: война бесконечности', 'Форсаж', 'Матрица'}

print(my_films.intersection(friends_films))
1
2
3
4
{'Мстители: война бесконечности', 'Форсаж'}
1

Упражнения

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

Напишите функцию print_valid_cities, которая сравнит множество всех городов all_cities со множеством названных городов used_cities и:

  • создаст множество городов, которые ещё можно использовать,
  • напечатает такое множество на экран, разделяя города запятой.
  • запустите эту функцию на примерах разных множеств и посмотрите, как она работает.
all_cities = set([ 'Абакан', 'Астрахань', 'Бобруйск', 'Калуга', 'Караганда', 'Кострома','Липецк', 'Новосибирск'])

used_cities = set(['Калуга', 'Абакан' , 'Новосибирск'])
1
2
3
  1. Научите Виту помогать вам с покупками в магазине. Вы хотите приготовить два блюда и рассказываете Вите, какие для них нужны продукты.

Напишите функцию print_shopping_list(), которая будет получать два списка продуктов — recipe1 и recipe2, и печатать на экран полный список покупок. Элементы в списке не должны повторяться.

pizza = ['мука', 'помидоры', 'шампиньоны', 'сыр', 'оливковое масло']
salad = ['огурцы', 'перцы', 'помидоры', 'оливковое масло', 'листья салата']
1
2
  1. Если вам надо 5 кг помидоров для салата и 3 кг для супа, вы сразу покупаете 8 килограммов.

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

pizza = {'мука, кг': 1,
         'помидоры, кг': 1.5,
         'шампиньоны, кг': 1.5,
         'сыр, кг': 0.8,
         'оливковое масло, л': 0.1,
         'дрожжи, г': 50}
salad = {'огурцы, кг': 1,
         'перцы, кг': 1,
         'помидоры, кг': 1.5,
         'оливковое масло, л': 0.1,
         'листья салата, кг': 0.4}
1
2
3
4
5
6
7
8
9
10
11

Результат должен получиться:

помидоры, кг: 3.0
огурцы, кг: 1
шампиньоны, кг: 1.5
дрожжи, г: 50
сыр, кг: 0.8
мука, кг: 1
перцы, кг: 1
листья салата, кг: 0.4
оливковое масло, л: 0.2
1
2
3
4
5
6
7
8
9

Проверка наличия элемента

В Python списки, словари и множества называются коллекции. Их можно легко различить по записи:

sleep_list = ['спать', 'дрыхнуть', 'кемарить', 'почивать', 'спать']  # список
sleep_dict = {'спать': 'дрыхнуть', 'почивать': 'кемарить'}  # словарь
sleep_set = {'дрыхнуть', 'спать', 'почивать', 'кемарить'}  # множество; фигурные скобки в этом случае то же, что вызов set()
1
2
3

Проверить, есть ли определённый элемент в списке или множестве, можно условной конструкцией оператором in (англ. in, «в»):

if 'почивать' in sleep_list:
    print('есть такое!')
# для всех трёх коллекций будет напечатано 'есть такое!'
1
2
3

Особенность есть у словарей — в них in засекает только ключи:

sleep_dict = {'спать': 'дрыхнуть', 'почивать': 'кемарить'}  # словарь
if 'дрыхнуть' in sleep_dict:
    print('есть такое!')
else:
    print('а что это?')
# 'дрыхнуть' — значение, соответствующее ключу 'спать', напечатается вопрос 'а что это?'
1
2
3
4
5
6

Когда нужно написать условие, что чего-нибудь в коллекции нет, помогает логический оператор not (англ. not, «не»)

# список животных в лесу Белого Рыцаря 
forest_list = ['лось', 'коза', 'барсук', 'глухарь', 'лиса', 'ёж', 'пчела', 'синица', 'заяц']

if 'слонёнок' not in forest_list:
    print('но нету слонёнка в лесу у меня,')
    print('слонёнка весёлого нет!')
1
2
3
4
5
6

У списков есть метод append() (англ. append, «добавлять в конец»), который добавляет свой аргумент в конец списка:

if 'баиньки' not in sleep_list:
    sleep_list.append('баиньки')  # метод append() добавляет строку 'баиньки' в конец списка
1
2

Можно написать функцию пополнения любых списков, назовём её new_one (англ. new one, «новичок»)

def new_one(some_list, new):
    if new in some_list:
        print('такое у нас уже есть')
    else:
        print('а это что-то новое, берём')
        some_list.append(new)
    print(some_list)

sleep_list = ['спать', 'дрыхнуть', 'кемарить', 'почивать', 'спать']
new_one(sleep_list, 'баиньки')
1
2
3
4
5
6
7
8
9
10

Результат:

а это что-то новое, берём
['спать', 'дрыхнуть', 'кемарить', 'почивать', 'спать', 'баиньки']
1
2

Упражнения

  1. Вы собираетесь поехать в Хабаровск. Было бы здорово встретиться там с друзьями. Но живет ли сейчас хоть кто-то из друзей в Хабаровске? Научите Анфису отвечать на этот вопрос — сделайте ей функцию is_anyone_in(collection, city)
friends = {
    'Серёга': 'Омск',
    'Соня': 'Москва',
    'Дима': 'Челябинск',
    'Алина': 'Хабаровск',
    'Егор': 'Пермь'
}

def is_anyone_in(collection, city):
    if city in ...:  # допишите код — если такое значение есть среди значений словаря collection
        for i in ...:  # допишите код — переберите все ключи словаря
            if ...:  # допишите код — и если соответствующее ключу значение равно city, тогда
                print('В городе ' + city + ' живёт ' + i + '.')

    else:
        print('Пока никого.')

is_anyone_in(friends, 'Хабаровск')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18