Перейти к содержанию

Кортежи

Мы уже знаем такие коллекции, как списки, множества и строки. Сегодня мы рассмотрим еще один тип данных, являющийся коллекцией, который называется tuple (читается «тюпл» или «тьюпл», а переводится как «кортеж»).

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

# кортеж из двух элементов; тип элементов может быть любой
card = ('7', 'пик')

# пустой кортеж (из 0 элементов)
empty = ()

# кортеж из 1 элемента - запятая нужна, чтобы отличить от
# обычных скобок
t = (18,)

# длина, значение отдельного элемента, сложение - как у списков
print(len(card), card[0], card + t)

Кортежи можно сравнивать между собой:

1
2
3
4
5
6
7
(1, 2) == (1, 3)    # False
(1, 2) < (1, 3)     # True
(1, 2) < (5,)       # True
('7', 'червей') < ('7', 'треф') # False

# А вот так сравнивать нельзя: элементы кортежей разных типов
(1, 2) < ('7', 'пик')

Обратите внимание: операции == и != применимы к любым кортежам, независимо от типов элементов. А вот операции <, >, <=, >= применимы только в том случае, когда соответствующие элементы кортежей имеют один тип. Поэтому сравнивать ('7', 'червей') и ('7', 'треф') можно, а вот кортежи (1, 2) и ('7', 'пик') нельзя — интерпретатор Python выдаст ошибку. При этом сравнение происходит последовательно элемент за элементом, а если элементы равны — просматривается следующий элемент.

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

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

Примечание

Хотя, конечно, ничто не мешает элементам списка иметь разный тип, а элементам кортежа — одинаковый.

Так, в примере выше кортеж card состоит из двух элементов, означающих достоинство карты и ее масть.

Еще одним приятным отличием кортежей от списков является то, что они могут быть элементами множества:

a = {('7', 'червей'), ('7', 'треф')}
print(a) # -> {('7', 'треф'), ('7', 'червей')}

Присваивание кортежей

Кортежи можно присваивать друг другу. Именно благодаря этому работает красивая особенность Python — уже знакомая нам конструкция вида a, b = b, a.

Как известно, по левую сторону от знака присваивания = должно стоять имя переменной либо имя списка с индексом или несколькими индексами. Они указывают, куда можно «положить» значение, записанное справа от знака присваивания. Однако слева от знака присваивания можно записать еще и кортеж из таких обозначений (грубо говоря, имен переменных), а справа — кортеж из значений, которые следует в них поместить. Значения справа указываются в том же порядке, что и переменные слева (здесь скобки вокруг кортежа необязательны):

1
2
3
4
n, s = 10, 'hello'
# то же самое, что
n = 10
s = 'hello'

В примере выше мы изготовили кортеж, стоящий справа от =, прямо на этой же строчке. Но можно заготовить его и заранее:

1
2
3
4
cards = [('7', 'пик'), ('Д', 'треф'), ('Т', 'пик')]
value, suit = cards[0]
print('Достоинство карты:', value)
print('Масть карты:', suit)

Самое приятное: сначала вычисляются все значения справа, и лишь затем они кладутся в левую часть оператора присваивания. Поэтому можно, например, поменять местами значения переменных a и b, написав: a, b = b, a.

a, b = 1, 2  # теперь a == 1 and b == 2
a, b = b, a  # теперь a == 2 and b == 1

Пример ниже выведет «1 2 3». Убедитесь, что вы понимаете, почему так.

1
2
3
4
# кручу-верчу
a, b, с = 3, 2, 1
b, a, c = c, a, b
print(b, c, a)

С использованием кортежей многие алгоритмы приобретают волшебную краткость. Например, вычисление чисел Фибоначчи:

1
2
3
4
5
n = int(input())
f1, f2 = 0, 1
for i in range(n):
    print(f2)
    f1, f2 = f2, f1 + f2

Сортировка пузырьком

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

Часто бывает нужно, чтобы данные не просто содержались в списке, а были отсортированы (например, по возрастанию), то есть чтобы каждый следующий элемент списка был не меньше предыдущего. В качестве данных могут выступать числа или строки. Скажем, отсортированный список [4, 1, 9, 3, 1] примет вид [1, 1, 3, 4, 9]. Конечно, для этого есть стандартные функции и методы, но как они работают?

Классический алгоритм сортировки — сортировка пузырьком (по-научному — сортировка обменом). Она называется так потому, что элементы последовательно «всплывают» (отправляются в конец списка), как пузырьки воздуха в воде. Сначала всплывает самый большой элемент, за ним — следующий по старшинству и т. д. Для этого мы сравниваем по очереди все соседние пары и при необходимости меняем элементы местами, ставя больший элемент на более старшее место.

n = int(input())    # количество элементов
a = []
for i in range(n):  # считываем элементы списка
    a.append(int(input()))
# Сортировка пузырьком:
for i in range(n - 1):
    for j in range(n - 1 - i):
        if a[j] > a[j + 1]:
            a[j], a[j + 1] = a[j + 1], a[j]
print(a)

Сортировка пузырьком

Преобразования между коллекциями

Итак, на данный момент мы знаем уже четыре вида коллекций: строки, списки, множества и кортежи. У вас может возникнуть вопрос: можно ли из одной коллекции сделать другую? Например, преобразовать строку в список или во множество? Конечно, да, для этого можно использовать функции list, set и tuple. Если в качестве аргумента передать этим функциям какую-либо коллекцию, новая коллекция будет создана на ее основе. Зачем нужно преобразование коллекций?

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

1
2
3
4
5
s = 'симпотичный'   # Написали с ошибкой
a = list(s)         # a == ['с', 'и', 'м', 'п', 'о', 'т', 'и,' 'ч', 'н',
                    #       'ы', 'й']
a[4] = 'а'          # a == ['с', 'и', 'м', 'п', 'а', 'т', 'и,' 'ч', 'н',
                    #       'ы', 'й']

С этой же целью может потребоваться преобразование кортежа в список:

1
2
3
4
# В кортеже (писатель, дата рождения) допущена ошибка
writer = ('Лев Толстой', 1827)
a = list(writer)                # a == ['Лев Толстой', 1827]
a[1] = 1828                     # a == ['Лев Толстой', 1828]

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

a = [1, 2, 1, 1, 2, 2, 3, 3]
print('Количество элементов в списке без повторений: ', len(set(a)))

Таким же образом можно получить все буквы без повторений, которые встречаются в строке:

a = set("Тетрагидропиранилциклопентилтетрагидропиридопиридиновые")
print(a, len(a))
{'л', 'н', 'в', 'о', 'и', 'ц', 'п', 'т', 'Т', 'г', 'ы', 'а', 'д', 'к',
 'р', 'е'} 16

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

1
2
3
4
5
6
7
names = {'Иван', 'Петр', 'Сергей', 'Алексей'}
print(list(names))
# Возможные варианты вывода на экран - ['Сергей', 'Алексей', 'Иван',
# 'Петр'],
# ['Сергей', 'Петр', 'Иван', 'Алексей'], ['Алексей', 'Иван', 'Петр',
# 'Сергей']
# и так далее.

Задачи

Задача 1

Считайте n чисел. Проверьте, является ли последнее число произведением каких-либо двух различных чисел из списка. Выведите ДА или НЕТ.

Тест 1:

Ввод:

5
37
3
99
55
111
Вывод:
ДА

Тест 2:

Ввод:

4
2
4
6
15
Вывод:
НЕТ


Задача 2

Считайте n пар фамилия оценка. Выведите все пары, затем пустую строку, затем только пары с оценкой 4 или 5.

Тест 1:

Ввод:

4
Иванов 5
Петров 3
Сидоров 4
Козлов 2
Вывод:
Иванов 5
Петров 3
Сидоров 4
Козлов 2

Иванов 5
Сидоров 4


Задача 3

Считайте n строк и выведите их в алфавитном порядке (используйте встроенную сортировку sorted()).

Тест 1:

Ввод:

4
три
четыре
пять
шесть
Вывод:
пять
три
четыре
шесть


Задача 4

Считайте n строк и выведите их отсортированными по длине (по возрастанию). Строки одинаковой длины — в алфавитном порядке.

Тест 1:

Ввод:

4
три
четыре
пять
шесть
Вывод:
три
пять
шесть
четыре


Задача 5

Выведите первые n чисел Фибоначчи (начиная с 1).

Тест 1:

Ввод:

7
Вывод:
1
1
2
3
5
8
13


Задача 6

Считайте n целых чисел и отсортируйте их пузырьком по возрастанию. Выведите отсортированный список.

Тест 1:

Ввод:

5
5
3
1
4
2
Вывод:
1
2
3
4
5


Задача 7

Считайте n чисел. Удалите из списка все дубликаты (оставьте уникальные значения) и выведите их количество.

Тест 1:

Ввод:

6
1
2
1
1
2
3
Вывод:
3


Задача 8

Считайте n пар чисел через пробел. Для каждой пары выведите их в порядке от меньшего к большему через пробел.

Тест 1:

Ввод:

3
5 2
1 9
4 4
Вывод:
2 5
1 9
4 4


Задача 9

Считайте n строк — каждая это фамилия рост. Выведите всех людей отсортированных по росту по убыванию.

Тест 1:

Ввод:

3
Иванов 170
Петров 185
Сидоров 162
Вывод:
Петров 185
Иванов 170
Сидоров 162


Задача 10

Считайте n строк и преобразуйте список строк в список кортежей (длина, строка). Выведите каждый кортеж на новой строке.

Тест 1:

Ввод:

3
кот
питон
яблоко
Вывод:
(3, 'кот')
(5, 'питон')
(6, 'яблоко')