"""Тема урока: кортежи
Перебор кортежей
Сравнение кортежей
Сортировка кортежей
Преобразование кортежа в список и строку
Упаковка кортежей
Распаковка кортежей
Присваивание кортежей
Аннотация. Урок посвящен кортежам (тип данных tuple).

Перебор кортежей
Перебор элементов кортежа осуществляется точно так же как перебор элементов списка.

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

Вариант 1. Если нужны индексы элементов:

numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

for i in range(len(numbers)):
    print(numbers[i])
Вариант 2. Если индексы не нужны:

numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

for num in numbers:
    print(num)
Можно также использовать операцию распаковки кортежа.

Приведенный ниже код:

numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
languages = ('Python', 'C++', 'Java')

print(*numbers)
print(*languages, sep='\n')
выводит:

0 1 2 3 4 5 6 7 8 9 10
Python
C++
Java
Сравнение кортежей
Кортежи можно сравнивать между собой.

Приведенный ниже код:

print((1, 8) == (1, 8))
print((1, 8) != (1, 10))
print((1, 9) < (1, 2))
print((2, 5) < (6,))
print(('a', 'bc') > ('a', 'de'))
выводит:

True
True
False
True
False
Обратите внимание: операции == и != применимы к любым кортежам, независимо от типов элементов. А вот
операции <, >, <=, >= применимы только в том случае, когда соответствующие элементы кортежей имеют один тип.

Приведенный ниже код:

print((7, 5) < ('java', 'python'))
выводит:

TypeError: '<' not supported between instances of 'int' and 'str'
Сравнение кортежей происходит последовательно элемент за элементом, а если элементы равны — просматривается следующий
 элемент.

Сортировка кортежей
Как мы помним, списки имеют метод sort(), который осуществляет сортировку на месте, то есть меняет порядок исходного
 списка. Поскольку кортежи по своей природе неизменяемы, то встроенного метода sort() они не содержат, тем не менее
 с помощью встроенной функции sorted() (не путать с списочным методом sort()) мы можем сортировать значения в кортежах.

Приведенный ниже код:

not_sorted_tuple = (34, 1, 8, 67, 5, 9, 0, 23)
print(not_sorted_tuple)

sorted_tuple = tuple(sorted(not_sorted_tuple))
print(sorted_tuple)
выводит:

(34, 1, 8, 67, 5, 9, 0, 23)
(0, 1, 5, 8, 9, 23, 34, 67)
Обратите внимание, что функция sorted() возвращает список, но с помощью функции tuple() мы приводим результат
сортировки к кортежу.

Для сортировки кортежа можно воспользоваться явным преобразованием в список и использовать метод sort():

not_sorted_tuple = ('cc', 'aa', 'dd', 'bb')
tmp = list(not_sorted_tuple)
tmp.sort()

sorted_tuple = tuple(tmp)
print(sorted_tuple)
Преобразование кортежа в список и строку
Часто на практике нам приходится преобразовывать кортежи в списки и в строки. Для этого используются функции и
 методы str(), list(), tuple(), join().

Преобразование кортежа в список и наоборот
Кортеж можно преобразовать в список с помощью функции list().

Приведенный ниже код:

tuple1 = (1, 2, 3, 4, 5)
list1 = list(tuple1)
print(list1)
выводит:

[1, 2, 3, 4, 5]
Список можно преобразовать в кортеж с помощью функции tuple().

Приведенный ниже код:

list1 = [1, 17.8, 'Python']
tuple1 = tuple(list1)
print(tuple1)
выводит:

(1, 17.8, 'Python')
Преобразование кортежа в строку и наоборот
Кортеж можно преобразовать в строку с помощью строкового метода join().

Приведенный ниже код:

notes = ('Do', 'Re', 'Mi', 'Fa', 'Sol', 'La', 'Si')
string1 = ''.join(notes)
string2 = '.'.join(notes)

print(string1)
print(string2)
выводит:

DoReMiFaSolLaSi
Do.Re.Mi.Fa.Sol.La.Si
Обратите внимание, что для применения строкового метода join() кортеж должен содержать именно строковые элементы.
Если элементы кортежа отличны от строк, то требуется предварительно их преобразовать.

Строку можно преобразовать в кортеж с помощью функции tuple().

Приведенный ниже код:

letters = 'abcdefghijkl'
tpl = tuple(letters)
print(tpl)
выводит:

('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l')
Обратите внимание, что следующий код:

number = 12345
tpl = tuple(number)
print(tpl)
приведет к ошибке:

TypeError: 'int' object is not iterable
поскольку тип данных int не является итерируемым объектом. Для преобразования числа в кортеж, сначала нужно число
 преобразовать в строку, а уже потом использовать функцию tuple()."""
'''Что будет выведено на экран в результате работы следующей программы?

poets = [
    ('Есенин', 13),
    ('Тургенев', 14),
    ('Маяковский', 28),
    ('Лермонтов', 20),
    ('Фет', 15)]

for i in range(len(poets)):
    for j in range(i+1, len(poets)):
        if poets[i][1] > poets[j][1]:
            poets[i], poets[j] = poets[j], poets[i]

print(poets[0])
print(poets[-1])
Подсказка

Вспоминаем сортировку пузырьком 😃'''
'''('Есенин', 13)
('Маяковский', 28)'''


'''Что будет выведено на экран в результате работы следующей программы?

poets = [
    ('Тургенев', 14),
    ('Есенин', 13),
    ('Маяковский', 28),
    ('Фет', 15),
    ('Лермонтов', 20)]

for i in range(len(poets)):
    for j in range(i+1, len(poets)):
        if poets[i] > poets[j]:
            poets[i], poets[j] = poets[j], poets[i]

print(poets[0])
print(poets[-1])
Подсказка
Кортежи сравниваются поэлементно.
'''
'''
('Есенин', 13)
('Фет', 15)'''

'''Дополните приведенный код так, чтобы он вывел произведение элементов кортежа numbers.'''
# numbers = (2, 3, 5, 7, -11, 13, 17, 19, 23, 29, 31, -6, 41, 43, 47, 53, 59, 61, -96, 71, 1000, -1)
# p = 1
# for i in numbers:
#     p *= i
# print(p)

# numbers = (2, 3, 5, 7, -11, 13, 17, 19, 23, 29, 31, -6, 41, 43, 47, 53, 59, 61, -96, 71, 1000, -1)
# print(__import__('functools').reduce(int.__mul__, numbers))

# numbers = (2, 3, 5, 7, -11, 13, 17, 19, 23, 29, 31, -6, 41, 43, 47, 53, 59, 61, -96, 71, 1000, -1)
# print(__import__('functools').reduce((lambda x, y: x * y), numbers))

'''Дополните приведенный код так, чтобы он преобразовал строку в кортеж символов строки и вывел результат.'''
# data = 'Python для продвинутых!'
# data = tuple(data)
# print(data)

'''Программист Тимур написал программу для работы с биографическими данными русских поэтов. Данные содержатся в 
кортежах вида (фамилия, год рождения, город рождения). В процессе работы программы в некотором кортеже poet_data
 обнаружилась ошибка: ('Пушкин', 1799, 'Санкт-Петербург'), неверно указано место рождения, ведь Александр Пушкин 
 родился в Москве.

Дополните приведенный код так, чтобы в переменной poet_data находился правильный кортеж (с исправленным значением), 
а затем выведите его содержимое.'''

# poet_data = ('Пушкин', 1799, 'Санкт-Петербург')
# poet_data = poet_data[:-1] + ('Москва',)
# print(poet_data)


'''Дополните приведенный код так, чтобы он вывел список, содержащий средние арифметические значения чисел каждого
 вложенного кортежа в заданном кортеже кортежей numbers.'''

# numbers = ((10, 10, 10, 12), (30, 45, 56, 45), (81, 80, 39, 32), (1, 2, 3, 4), (90, 10))
# new_numbers = ([sum(t)/len(t) for t in numbers])
# print(new_numbers)

# numbers = ((10, 10, 10, 12), (30, 45, 56, 45), (81, 80, 39, 32), (1, 2, 3, 4), (90, 10))
# print([sum(_)/len(_) for _ in numbers])


'''Вершина параболы
Уравнение параболы имеет вид y =ax^2 + bx + c, a!=0. Напишите программу, которая по введенным значениям a, b, c
 определяет и выводит вершину параболы.
Формат входных данных
На вход программе подаются три целых числа, каждое на отдельной строке.
Формат выходных данных
Программа должна вывести координаты вершины параболы.
Примечание. Координаты вершины параболы y=ax^2+bx+c

Sample Input 1:

-2
6
1
Sample Output 1:

(1.5, 5.5)
Sample Input 2:

-5
2
0
Sample Output 2:

(0.2, 0.2)'''

# a = int(input())
# b = int(input())
# c = int(input())
#
# k = (-b/(2*a), ((4*a*c)-(b**2))/(4*a))
# print(k)

# (lambda a, b, c: print((-b / (2 * a), (4 * a * c - b ** 2) / (4 * a))))(*[float(input()) for _ in range(3)])


# a, b, c = int(input()), int(input()), int(input())
# print((-b/2/a, (4*a*c-b**2)/4/a))


'''Конкурсный отбор
Напишите программу, которая выводит список хорошистов и отличников в классе.

Формат входных данных
На вход программе подается натуральное число nn, далее следует nn строк с фамилией школьника и его оценкой на каждой из них.

Формат выходных данных
Программа должна вывести сначала все введённые строки с фамилиями и оценками учеников в том же порядке. Затем следует пустая строка, а затем выводятся строки с фамилиями и оценками хорошистов и отличников (в том же порядке).

Примечание 1. Оценка ученика – это натуральное число от 11 до 55.

Примечание 2. Гарантируется, что в классе есть хотя бы один хорошист – обладатель оценки 44, или отличник – получивший 55.

Sample Input 1:

3
Гуев 3
Чаниев 5
Барсуков 2
Sample Output 1:

Гуев 3
Чаниев 5
Барсуков 2

Чаниев 5'''


# n = int(input())
# arr = [tuple(input().split()) for _ in range(n)]
# for c in tuple(arr):
#     print(*c)
# print()
# for i in arr:
#     if tuple(i[-1])>tuple('3'):
#         print(*i)

# data = [tuple(input().split()) for _ in range(int(input()))]
#
# for user in data:
#     print(user[0], user[1])
#
# print()
#
# for user in data:
#     if int(user[1]) > 3:
#         print(user[0], user[1])

# pup = [input() for _ in range(int(input()))]
# print(*pup, sep='\n')
# print()
# [print(x) for x in pup if int(x[-1]) > 3]

# lst = [input() for _ in range(int(input()))]
# print(*lst, sep='\n')
# print()
# print(*[s for s in lst if s[-1] in '45'], sep='\n')


'''Упаковка кортежей
Упаковкой кортежа называют присваивание его какой-либо переменной.

Приведенный ниже код:

tuple1 = (1, 2, 3)
tuple2 = ('b',)
tuple3 = ('red', 'green', 'blue', 'cyan')

print(type(tuple1))
print(type(tuple2))
print(type(tuple3))
выводит:

<class 'tuple'>
<class 'tuple'>
<class 'tuple'>


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

Приведенный ниже код автоматически запакует 1, 2, 3 и 'b', в кортежи (1, 2, 3) и ('b', ) и присвоит их значения
 переменным tuple1 и tuple2:

tuple1 = 1, 2, 3
tuple2 = 'b',

print(type(tuple1))
print(type(tuple2))
выводит:

<class 'tuple'>
<class 'tuple'>
Распаковка кортежей
Обратная операция, смысл которой в том, чтобы присвоить значения элементов кортежа отдельным переменным называется 
распаковкой кортежа.

Приведенный ниже код:

colors = ('red', 'green', 'blue', 'cyan')

(a, b, c, d) = colors

print(a)
print(b)
print(c)
print(d)
выводит:

red
green
blue
cyan
В приведенном примере кортеж colors распаковывается в переменные a, b, c, d.



Мы можем опустить скобки слева от знака равенства:

colors = ('red', 'green', 'blue', 'cyan')
a, b, c, d = colors
Количество переменных должно совпадать с числом элементов в кортеже.

Приведенный ниже код:

colors = ('red', 'green', 'blue', 'cyan')
a, b = colors
приводит к ошибке:

ValueError: too many values to unpack
Аналогично, приведенный ниже код: 

colors = ('red', 'green', 'blue')
a, b, c, d = colors
приводит к ошибке:

ValueError: not enough values to unpack (expected 4, got 3)
Однако, если необходимо получить лишь какие-то отдельные значения, то в качестве "ненужных" переменных позволено
 использовать символ нижнего подчеркивания _.

Приведенный ниже код:

colors = ('red', 'green', 'blue')
a, b, _ = colors

print(a)
print(b)
выводит:

red
green
Распаковка кортежей очень удобна на практике. По сути мы использовали ее, когда меняли местами значения двух 
переменных без использования временных переменных.

Приведенный ниже код:

a = 7
b = 17
a, b = b, a

print(a, b)
выводит:

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

Приведенный ниже код:

a, b, c = 3, 2, 1
b, a, c = c, a, b

print(b, c, a)
выводит:

1 2 3
* при распаковке кортежей
Как мы знаем, если при распаковке кортежа число элементов слева и справа не совпадает, то возникает ошибка времени 
исполнения. Есть способ собрать сразу несколько значений в одну переменную. Это делается при помощи звездочки перед
 именем переменной.

Рассмотрим программный код:

a, b, *tail = 1, 2, 3, 4, 5, 6
В этом случае в переменной a будет записана единица, в переменной b — двойка, а в переменной tail — список, состоящий
 из всех аргументов, которые не попали в предыдущие переменные. В данном случае tail будет равен [3, 4, 5, 6].

Учтите, что tail всегда будет списком, даже когда в него попадает лишь один элемент или даже ноль.

Приведенный ниже код:

a, b, *tail = 1, 2, 3

print(tail)
выводит:

[3]
Приведенный ниже код:

a, b, *tail = 1, 2

print(tail)
выводит:

[]
Звездочка может быть только у одного аргумента, но необязательно у последнего.

Приведенный ниже код:

*names, surname = ('Стефани', 'Джоанн', 'Анджелина', 'Джерманотта')

print(names)
print(surname)
выводит:

['Стефани', 'Джоанн', 'Анджелина']
Джерманотта
Аргумент со звездочкой может стоять и посередине.

singer = ('Freddie', 'Bohemian Rhapsody', 'Killer Queen', 'Love of my life', 'Mercury')

name, *songs, surname = singer

print(name)
print(songs)
print(surname)
выводит:

Freddie
['Bohemian Rhapsody', 'Killer Queen', 'Love of my life']
Mercury
Примечания
Примечание 1. Если вы хотите распаковать единственное значение в кортеже, после имени переменной должна идти запятая.

Приведенный ниже код:

a = 1,      # не распаковка, а просто присвоение
b, = 1,     # распаковка

print(a)
print(b)
выводит:

(1,)
1
Примечание 2. Распаковывать можно не только кортеж, правая сторона может быть любой последовательностью 
(кортеж, строка или список).

info = ['timur', 'beegeek.org']
user, domain = info    # распаковка списка

print(user)
print(domain)

a, b, c, d = 'math'    # распаковка строки

print(a)
print(b)
print(c)
print(d)
выводит:

timur
beegeek.org
m
a
t
h
Примечание 3. Помимо метода split() строковый тип данных содержит метод partition(). Метод partition() принимает на 
вход один аргумент sep, разделяет строку при первом появлении sep и возвращает кортеж, состоящий из трех элементов: 
часть перед разделителем, сам разделитель и часть после разделителя. Если разделитель не найден, то кортеж содержит 
саму строку, за которой следуют две пустые строки.

Приведенный ниже код:

s1 = 'abc-de'.partition('-')
s2 = 'abc-de'.partition('.')
s3 = 'abc-de-fgh'.partition('-')

print(s1)
print(s2)
print(s3)
выведет:

('abc', '-', 'de')
('abc-de', '', '')
('abc', '-', 'de-fgh')
Примечание 4. С использованием кортежей многие алгоритмы приобретают достаточно краткую форму. Например, вычисление 
чисел Фибоначчи может выглядеть следующим образом:

n = int(input())
f1, f2 = 0, 1
for i in range(n):
    print(f2)
    f1, f2 = f2, f1 + f2
Примечание 5. Замечательная серия статей о коллекциях (list, tuple, str, set, dict) в Python.

'''

'''Последовательность Трибоначчи 🌶️
Напишите программу, которая считывает натуральное число nn и выводит первые nn чисел последовательности Трибоначчи.

Формат входных данных
На вход программе подается одно число n\,  (n \le 100)n (n≤100) – количество членов последовательности.

Формат выходных данных
Программа должна вывести члены последовательности Трибоначчи, отделенные символом пробела.

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

1,1, 1, 3, 5, 9, 17, 31, 57, 105 …'''

# def createTribonacci(limit, init=(2, 0, -1, 1)):
#     a, b, c, d = init
#     for _ in range(limit):
#         a, b, c, d = b, c, d, 2 * d - a
#         yield d
#
#
# limit = int(input())
#
# gen = createTribonacci(limit, init=(-3, 1, 1, -1))
# print(*gen)

# n = int(input())
# t1 = t2 = t3 = 1
# for _ in range(n):
#     print(t1, end=' ')
#     t1, t2, t3 = t2, t3, t1 + t2 + t3

# a, b, c = 1, 1, 1
# n = int(input())
# for x in range(n):
#     print(a, end=' ')
#     a, b, c = b, c, a + b + c
