Списки, кортежи и множества

Все курсы > Программирование на Питоне > Занятие 7

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

Вначале откроем ноутбук к этому занятию

Списки

Мы начали изучать списки на пятом занятии вводного курса. Продолжим эту работу.

Основы работы со списками

Список можно создать (или как правильнее говорить инициализировать) через пустые квадратные скобки [] или с помощью функции list().

Элементом списка может быть любой объект, например, число, строка, список или словарь.

Длину списка можно узнать с помощью функции len().

Индекс и срез списка

Как мы уже знаем, у списка есть индекс. Элементы списка индексируются так же, как символы в строке.

индекс списка в Питоне

Рассмотрим пример со вложенными списками (nested list). Для того чтобы обратиться, например, к первому элементу второго вложенного списка нужно использовать двойной индекс [1][0].

Обратите внимание, мы начали с индекса вложенного списка ['Игорь', 85000] в общем списке salary_list (как бы снаружи). Он соответствует [1]. Затем мы указали индекс первого элемента внутри вложенного списка [0].

Индекс элемента в списке можно узнать с помощью метода .index(). Предположим, мы хотим узнать индекс элемента 'c' в списке abc_list.

Метод .index() можно применить ко вложенному списку.

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

У среза есть третий параметр — шаг. Он позволяет пропускать заданное количество элементов.

Кроме того, мы можем проверить содержится ли элемент в списке с помощью ключевого слова in.

Добавление, замена и удаление элементов списка

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

Метод .insert() позволяет добавить элемент в середину списка, при этом индекс последующих элементов сдвигается.

Элемент списка можно заменить по индексу.

Элемент можно удалить, указав либо его название, либо индекс.

Все эти операции возможны благодаря тому, что списки (1) упорядочены и (2) изменяемы.

Убедимся, что остался только понедельник.

Сложение списков

Добавить к списку еще один список можно с помощью метода .extend(). Мы с вами уже использовали его на занятии по обработке естественного языка.

Кроме того, два списка можно просто сложить (concatenate).

Распаковка списков

Ранее мы уже познакомились с возможностью распаковки списков (unpacking), то есть помещения элементов списка в переменные. Теперь посмотрим на этот функционал более внимательно.

Во-первых, элемент можно вывести по индексу и поместить в переменную.

Несколько элементов можно поместить сразу в несколько переменных. Количество передаваемых элементов можно регулировать срезом.

Если нас интересует только первый элемент списка, но мы не хотим использовать индекс, можно распаковать список в две переменные, пометив вторую символом *. В первую попадет первый элемент, во вторую — все остальные.

Аналогичным образом мы можем распаковать первый, *остальные и последний элементы списка.

Сортировка списков

Для сортировки списка можно использовать функцию sorted() и метод .sort(). Функция sorted() не изменяет объект и сразу выводит результат сортировки.

Впрочем, если записать результат вызова функции sorted() в переменную, изменение станет постоянным.

Метод .sort() изменяет сам объект, но результат сортировки нужно вывести отдельно.

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

Преобразование списка в строку

Мы с вами уже умеем разбивать строку на части и превращать в список. Иногда бывает полезно сделать обратное.

Возьмем список, состоящий из букв.

И преобразуем его в строку с помощью метода .join(). Обратите внимание, пространство между элементами списка мы ничем не заполняем и для этого оставляем кавычки пустыми ''.

Конечно, мы можем указать любой другой межбуквенный элемент.

Арифметика в списках

Вновь создадим список, состоящий из чисел.

С помощью метода .count() мы можем посчитать частоту вхождения элемента в список.

Функции min(), max() и sum() позволяют рассчитать минимальное и максимальное значение, а также сумму элементов списка.

List comprehension

А теперь рассмотрим list comprehension. По сути, list comprehension позволяет превратить один список в другой, преобразовывая и отбирая элементы исходного списка.

list comprehension в Питоне

Рассмотрим на примерах. Предположим, у нас есть список имен.

И на основе этого списка мы хотим создать новый список, в котором останутся только имена, начинающиеся с буквы «А». Очевидно, мы можем использовать цикл for.

List comprehension позволяет сделать то же самое, но в одну строку.

Немного изменив код, мы можем перевести все заглавные буквы имен исходного списка в строчные.

На основе этих двух примеров давайте разберемся с синтаксисом list comprehension.

схема list comprehension
  • Вначале идет выражение, преобразующее каждый элемент исходного списка.
    • Если просто указать переменную, как это было в первом примере с переменной name, элементы перейдут из исходного списка в новый без изменений.
    • Во втором примере, мы изменили регистр с заглавной буквы на строчную с помощью метода .lower().
  • Затем идет блок, по сути, повторяющий цикл for.
  • И наконец, если это необходимо, условие c if, с помощью которого мы можем отобрать не все, а лишь некоторые из элементов исходного списка.

Приведу еще один пример.

Как вы видите, здесь схема немного изменилась. Интерпретировать эту запись можно следующим образом:

  • name if name != 'Виктор' — оставь элемент в списке без изменений, если он не совпадает с именем «Виктор»
  • else 'Вадим' — в противном случае (т.е. если совпадает), замени на Вадим
  • for name in names — сделай все это, проходясь по элементам исходного списка

Также напомню, что мы уже использовали list comprehension на занятии по обработке естественного языка. Мы брали список слов после лемматизации.

И применяли стеммер к каждому из элементов списка с помощью list comprehension.

Кортежи

Кортеж (tuple) инициализируется при помощи круглых скобок () или функции tuple().

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

Основное отличие от списка — кортеж неизменяем. После того как кортеж создан, добавлять или удалять элементы нельзя.

Например, заменить элемент по его индексу нельзя.

ошибка при попытке изменения элемента кортежа

Для этого придется вначале преобразовать кортеж в список.

Создать кортеж из одного элемента можно с помощью запятой.

Если запятую не ставить, получится строка.

Функция enumerate()

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

Просмотр элементов словаря

Аналогично, если в цикле for к словарю применить знакомый нам метод .items() и использовать только одну переменную, мы получим кортежи из ключа и значения.

Распаковка кортежей

Распаковать кортеж значит поместить каждый из его элементов в отдельную переменную.

Кортежи удобно распаковывать в цикле for.

С элементами словаря получается то же самое.

Здесь на самом деле ничего нового для нас нет.

Создание кортежа через функцию zip()

Функция zip() принимает два и более списков и формирует объект из кортежей. В первом кортеже содержатся первые элементы каждого из списков, во втором — вторые и так далее.

функция zip() в Питоне

Получившийся zip-объект нужно преобразовать в список.

Множества

Про множества важно запомнить три факта:

  • Элементы множества изменять нельзя
  • Множество — это набор уникальных элементов, а значит повторы в нем удаляются
  • У множества нет индекса, элементы не упорядочены

Создание множества

Множество можно создать с помощью функции set() или перечислив элементы в фигурных скобках {}.

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

Это опять же говорит об уникальности и неупорядоченности элементов множества.

Пустыми фигурные скобки оставлять нельзя. Это способ создания словаря.

Добавление и удаление элементов

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

Метод .add() позволяет добавить элемент во множество. Например, букву «я».

Несколько элементов можно добавить с помощью метода .update().

Если мы по ошибке добавим согласную букву, например, «щ».

Ее можно удалить с помощью метода .remove().

Теория множеств в Питоне

Разумеется, объект множества в Питоне согласуется с математической теорией множеств (set theory).

Основные понятия

В частности, мы знаем, что равные множества — это множества, состоящие из одних и тех же элементов (при этом порядок элементов не важен). Питон позволяет это проверить.

Мощность множества или его кардинальное число отражает количество элементов множества и рассчитывается с помощью знакомой нам функции len().

Мы также можем проверить принадлежность элемента определенному множеству.

Подмножество и надмножество

Одно множество, назовем его A, называется подмножеством (subset) другого множества B, если все элементы множества A также принадлежат и множеству B. Питон позволяет это проверить с помощью метода .issubset().

Множество B называется надмножеством (superset) A, если A является подмножеством B. По сути, это обратная логическая операция, для которой есть метод .issuperset().

Объединение, пересечение и разность множеств

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

Объединение множеств (union) отражает логическую операцию ИЛИ и нашем случае мы выберем тех специалистов, которые состоят хотя бы в одной команде. Другими словами, принадлежат или одному, или другому множеству, или обоим сразу.

Как мы видим есть два способа задать объединение множеств: через метод .union() или с помощью символа |. Аналогичные возможности есть и для других операций с множествами.

На диаграмме Эйлера это будут и те, кто входит в круг cv, и те, кто входит в nlp, и их пересечение.

объединение множеств, круги Эйлера

При пересечении множеств (intersection) осуществляется логическая операция И. Мы выбираем только тех людей, которые работают в обеих командах, т.е. принадлежат обоим множествам.

На кругах Эйлера это опять же пересечение.

пересечение множеств, круги Эйлера

Разность множеств (difference) nlp и cv позволяет увидеть, кто в команде по обработке естественного языка занимается только этой областью, и не учавствует в проектах по компьютерному зрению.

разность множеств, круги Эйлера

И наоборот, если мы смотрим на разность cv и nlp, то оставляем только тех, кто специализируется на компьютерном зрении.

еще одна разность множеств, круги Эйлера

Наконец, симметричная разность (symmetric difference) множеств объединяет обе предыдущие операции разности.

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

симметричная разность множеств, круги Эйлера

Подведем итог

Мы подробно рассмотрели три относящихся к коллекциям структуры данных, а именно списки, кортежи и множества.

Списки изменяемы и упорядочены. Кортежи упорядочены, но не изменяемы. Множества не упорядочены и не изменяемы. Кроме того, множества всегда содержат только уникальные элементы, повторы не допускаются.

Вопросы для закрепления

Как вывести элемент вложенного списка по его индексу?

Ответ: вначале нужно указать индекс вложенного списка, а затем индекс элемента внутри этого вложенного списка.

Как выглядит основная схема list comprehension?

Ответ: что делать с элементом : цикл for : при каком условии if. Обратите внимание, если мы хотим использовать if-else схема отличается (см. пример выше).

Что такое симметричная разность двух множеств?

Ответ: симметричная разность двух множеств включает элементы двух множеств, не являющихся для них общими.

В ноутбуке к лекции приведены дополнительные упражнения⧉.

На следующем занятии мы поговорим про словари в Питоне и на этом завершим разбор коллекций.