<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Кафедра дискретной математики МФТИ
Курс математической статистики
Никита Волков
На основе http
Step1:  Скобки ставить не обязательно, если кортеж - единственная вещь в правой части присваивания.
Step2:  Работать с кортежами можно так же, как со списками. Нельзя только изменять их.
Step3:  В левой части присваивания можно написать несколько переменных через запятую, а в правой кортеж. Это одновременное присваивание значений нескольким переменным.
Step4:  Сначала вычисляется кортеж в правой части, исходя из старых значений переменных (до этого присваивания). Потом одновременно всем переменным присваиваются новые значения из этого кортежа. Поэтому так можно обменять значения двух переменных.
Step5:  Это проще, чем в других языках, где приходится использовать третью переменную.
Множества
В соответствии с математическими обозначениями, множества пишутся в фигурных скобках. Элемент может содержаться в множестве только один раз. Порядок элементов в множестве не имеет значения, поэтому питон их сортирует. Элементы множества могут быть любых типов.
Step6:  Принадлежит ли элемент множеству?
Step7:  Множество можно получить из списка, или строки, или любого объекта, который можно использовать в for цикле (итерабельного).
Step8:  Как записать пустое множество? Только так.
Step9:  Дело в том, что в фигурных скобках в питоне пишутся также словари (мы будем их обсуждать в следующем параграфе). Когда в них есть хоть один элемент, можно отличить словарь от множества. Но пустые фигурные скобки означают пустой словарь.
Step10:  Работать с множествами можно как со списками.
Step11:  Это генератор множества (set comprehension).
Step12:  Объединение множеств.
Step13:  Проверка того, является ли одно множество подмножеством другого.
Step14:  Пересечение.
Step15:  Разность и симметричная разность.
Step16:  Множества (как и списки) являются изменяемыми объектами. Добавление элемента в множество и исключение из него.
Step17:  Как и в случае +=, можно скомбинировать теоретико-множественную операцию с присваиванием.
Step18:  Приведенные выше операции можно записывать и в другом стиле
Step19:  Существуют также неизменяемые множества. Этот тип данных называется frozenset. Операции над такими множествами подобны обычным, только невозможно изменять их (добавлять и исключать элементы).
Словари
Словарь содержит пары ключ - значение (их порядок несущественен). Это один из наиболее полезных и часто используемых типов данных в питоне.
Step20:  Можно узнать значение, соответствующее некоторому ключу. Словари реализованы как хэш-таблицы, так что поиск даже в больших словарях очень эффективен. В языках низкого уровня (например, C) для построения хэш-таблиц требуется использовать внешние библиотеки и писать заметное количество кода. В скриптовых языках (perl, python, php) они уже встроены в язык, и использовать их очень легко.
Step21:  Можно проверить, есть ли в словаре данный ключ.
Step22:  Можно присваивать значения как имеющимся ключам, так и отсутствующим (они добавятся к словарю).
Step23:  Длина - число ключей в словаре.
Step24:  Можно удалить ключ из словаря.
Step25:  Метод get, если он будет вызван с отсутствующим ключом, не приводит к ошибке, а возвращает специальный объект None. Он используется всегда, когда необходимо указать, что объект отсутствует (в какой-то мере он аналогичен null в C). Если передать методу get второй аргумент - значение по умолчанию, то будет возвращаться это значение, а не None.
Step26:  Словари обычно строят последовательно
Step27:  А это генератор словаря (dictionary comprehension).
Step28:  Ключами могут быть любые неизменяемые объекты, например, целые числа, строки, кортежи.
Step29:  Словари, подобно спискам, можно использовать в for циклах. Перебираются имеющиеся в словаре ключи (в каком-то непредсказуемом порядке).
Step30:  Метод keys возвращает список ключей, метод values - список соответствующих значений (в том же порядке), а метод items - список пар (ключ,значение). Точнее говоря, это не списки, а некоторые объекты, которые можно использовать в for циклах или превратить в списки функцией list. Если хочется написать цикл по упорядоченному списку ключей, то можно использовать sorted(d.keys)).
Step31:  Что есть истина? И что есть ложь? Подойдём к этому философскому вопросу экспериментально.
Step32:  На выражения, стоящие в булевых позициях (после if, elif и while), неявно напускается функция bool. Некоторые объекты интерпретируются как False
Step33:  Эта функция более полезна
Step34:  Если у функции много параметров, то возникает желание вызывать её попроще в наиболее часто встречающихся случаях. Для этого в операторе def можно задать значения некоторых параметров по умолчанию (они должны размещаться в конце списка параметров). При вызове необходимо указать все обязательные параметры (у которых нет значений по умолчанию), а необязательные можно и не указывать. Если при вызове указывать параметры в виде имя=значение, то это можно делать в любом порядке. Это гораздо удобнее, чем вспоминать, является данный параметр восьмым или девятым при вызове какой-нибудь сложной функции. Обратите внимание, что в конструкции имя=значение не ставятся пробелы между символом =.
Step35:  Переменные, использующиеся в функции, являются локальными. Присваивание им не меняет значений глобальных переменных с такими же именами.
Step36:  Если в функции нужно использовать какие-нибудь глобальные переменные, их нужно описать как global.
Step37:  Пространство имён устанавливает соответствие между именами переменных и объектами - их значениями. Есть пространство имён локальных переменных функции, пространство имён глобальных переменных программы и пространство имён встроенных функций языка питон. Для реализации пространств имён используются словари.
Если функции передаётся в качестве аргумента какой-нибудь изменяемый объект, и функция его изменяет, то это изменение будет видно снаружи после этого вызова. Мы уже обсуждали эту ситуацию, когда две переменные (в данном случае глобальная переменная и параметр функции) указывают на один и тот же изменяемый объект объект.
Step38:  Если в качестве значения какого-нибудь параметра по умолчанию используется изменяемый объект, то это может приводить к неожиданным последствиям. В данном случае исполнение определения функции приводит к созданию двух объектов
Step39:  Чтобы избежать таких сюрпризов, в качестве значений по умолчанию лучше использовать только неизменяемые объекты.
Step40:  Эта функция имеет один обязательный параметр плюс произвольное число необязательных. При вызове все такие дополнительные аргументы объединяются в кортеж, который функция может использовать по своему усмотрению.
Step41:  Звёздочку можно использовать и при вызове функции. Можно заранее построить список (или кортеж) аргументов, а потом вызвать функцию с этими аргументами.
Step42:  Такую распаковку из списков и кортежей можно использовать не только при вызове функции, но и при построении списка или кортежа.
Step43:  Эта функция имеет два обязательных параметра плюс произвольное число необязательных ключевых параметров. При вызове они должны задаваться в виде имя=значение. Они собираются в словарь, который функция может использовать по своему усмотрению.
Step44:  Двойную звёздочку можно использовать и при вызове функции. Можно заранее построить словарь аргументов, сопоставляющий значения именам параметров, а потом вызвать функцию с этими ключевыми аргументами.
Step45:  Вот любопытный способ построить словарь с ключами-строками.
Step46:  Двойную звёздочку можно использовать не только при вызове функции, но и при построении словаря.
Step47:  Вот простой способ объединить два словаря.
Step48:  Если один и тот же ключ встречается несколько раз, следующее значение затирает предыдущее.
Step49:  Это наиболее общий вид списка параметров функции. Сначала идут обязательные параметры (в данном случае два), затем произвольное число необязательных (при вызове они будут объединены в кортеж), а затем произвольное число ключевых параметров (при вызове они будут объединены в словарь).
Step50:  В питоне функции являются гражданами первого сорта. Они могут присутствовать везде, где допустимы объекты других типов - среди элементов списков, значений в словарях и т.д.
Step51:  Если Вы пишете функцию не для того, чтобы один раз её вызвать и навсегда забыть, то нужна документация, объясняющая, что эта функция делает. Для этого сразу после строчки def пишется строка. Она называется док-строкой, и сохраняется при трансляции исходного текста на питоне в байт-код (в отличие от комментариев, которые при этом отбрасываются). Обычно эта строка заключается в тройные кавычки и занимает несколько строчек. Док-строка доступна как атрибут __doc__ функции, и используется функцией help. Вот пример культурно написанной функции, вычисляющей $n$-е число Фибоначчи.
Для проверки типов аргументов, переданных функции, удобно использовать оператор assert. Если условие в нём истинно, всё в порядке, и он ничего не делает; если же оно ложно, выдаётся сообщение об ошибке.
Step52:  В jupyter-ноутбуке к документации можно обращаться более удобным способом
Step53:  Некоторые полезные функции
zip скрещивает два массива одной длины
Step54:  map применяет функию к каждому элементу массива
Step55:  sorted --- сортировка
<ASSISTANT_TASK:>
Python Code:
(1, 2, 3)
()
(1,)
Explanation: Кафедра дискретной математики МФТИ
Курс математической статистики
Никита Волков
На основе http://www.inp.nsk.su/~grozin/python/
Кортежи
Кортежи (tuples) очень похожи на списки, но являются неизменяемыми. Как мы видели, использование изменяемых объектов может приводить к неприятным сюрпризам.
Кортежи пишутся в круглых скобках. Если элементов $>1$ или 0, это не вызывает проблем. Но как записать кортеж с одним элементом? Конструкция (x) абсолютно легальна в любом месте любого выражения, и означает просто x. Чтобы избежать неоднозначности, кортеж с одним элементом x записывается в виде (x,).
End of explanation
t = 1, 2, 3
t
Explanation: Скобки ставить не обязательно, если кортеж - единственная вещь в правой части присваивания.
End of explanation
len(t)
t[1]
u = 4, 5
t + u
2 * u
Explanation: Работать с кортежами можно так же, как со списками. Нельзя только изменять их.
End of explanation
x, y = 1, 2
x
y
Explanation: В левой части присваивания можно написать несколько переменных через запятую, а в правой кортеж. Это одновременное присваивание значений нескольким переменным.
End of explanation
x, y = y, x
x
y
Explanation: Сначала вычисляется кортеж в правой части, исходя из старых значений переменных (до этого присваивания). Потом одновременно всем переменным присваиваются новые значения из этого кортежа. Поэтому так можно обменять значения двух переменных.
End of explanation
s = {0, 1, 0, 5, 5, 1, 0}
s
Explanation: Это проще, чем в других языках, где приходится использовать третью переменную.
Множества
В соответствии с математическими обозначениями, множества пишутся в фигурных скобках. Элемент может содержаться в множестве только один раз. Порядок элементов в множестве не имеет значения, поэтому питон их сортирует. Элементы множества могут быть любых типов.
End of explanation
1 in s, 2 in s, 1 not in s
Explanation: Принадлежит ли элемент множеству?
End of explanation
l = [0, 1, 0, 5, 5, 1, 0]
set(l)
set('абба')
Explanation: Множество можно получить из списка, или строки, или любого объекта, который можно использовать в for цикле (итерабельного).
End of explanation
set()
Explanation: Как записать пустое множество? Только так.
End of explanation
{}
Explanation: Дело в том, что в фигурных скобках в питоне пишутся также словари (мы будем их обсуждать в следующем параграфе). Когда в них есть хоть один элемент, можно отличить словарь от множества. Но пустые фигурные скобки означают пустой словарь.
End of explanation
len(s)
for x in s:
    print(x)
Explanation: Работать с множествами можно как со списками.
End of explanation
{i for i in range(5)}
Explanation: Это генератор множества (set comprehension).
End of explanation
s2 = s | {2, 5}
s2
Explanation: Объединение множеств.
End of explanation
s < s2, s > s2, s <= s2, s >= s2
Explanation: Проверка того, является ли одно множество подмножеством другого.
End of explanation
s2 & {1, 2, 3}
Explanation: Пересечение.
End of explanation
s2 - {1,3,5}
s2 ^ {1,3,5}
Explanation: Разность и симметричная разность.
End of explanation
s2.add(4)
s2
s2.remove(1)
s2
Explanation: Множества (как и списки) являются изменяемыми объектами. Добавление элемента в множество и исключение из него.
End of explanation
s2 |= {1, 2}
s2
Explanation: Как и в случае +=, можно скомбинировать теоретико-множественную операцию с присваиванием.
End of explanation
x = set([1, 4, 2, 4, 2, 1, 3, 4])
print(x)
x.add(5)  # добавление элемента
print(x)
x.pop()  # удаление элемента
print(x)
print(x.intersection(set([2, 4, 6, 8])))  # Пересечение
print(x.difference(set([2, 4, 6, 8])))  # Разность
print(x.union(set([2, 4, 6, 8])))  # Объединение
print(x.symmetric_difference(set([2, 4, 6, 8])))  # Симметрическая разность
print(x.issubset(set([2, 4, 6, 8])))  # Является ли подмножеством
print(x.issubset(set(list(range(10)))))
print(x.issuperset(set([2, 4, 6, 8])))  # Является ли надмножеством
print(x.issuperset(set([2, 4])))
Explanation: Приведенные выше операции можно записывать и в другом стиле
End of explanation
d = {'one': 1, 'two': 2, 'three': 3}
d
Explanation: Существуют также неизменяемые множества. Этот тип данных называется frozenset. Операции над такими множествами подобны обычным, только невозможно изменять их (добавлять и исключать элементы).
Словари
Словарь содержит пары ключ - значение (их порядок несущественен). Это один из наиболее полезных и часто используемых типов данных в питоне.
End of explanation
d['two']
d['four']
Explanation: Можно узнать значение, соответствующее некоторому ключу. Словари реализованы как хэш-таблицы, так что поиск даже в больших словарях очень эффективен. В языках низкого уровня (например, C) для построения хэш-таблиц требуется использовать внешние библиотеки и писать заметное количество кода. В скриптовых языках (perl, python, php) они уже встроены в язык, и использовать их очень легко.
End of explanation
'one' in d, 'four' in d
Explanation: Можно проверить, есть ли в словаре данный ключ.
End of explanation
d['one'] =- 1
d
d['four'] = 4
d
Explanation: Можно присваивать значения как имеющимся ключам, так и отсутствующим (они добавятся к словарю).
End of explanation
len(d)
Explanation: Длина - число ключей в словаре.
End of explanation
del d['two']
d
Explanation: Можно удалить ключ из словаря.
End of explanation
d.get('one'), d.get('five')
d.get('one', 0), d.get('five', 0)
Explanation: Метод get, если он будет вызван с отсутствующим ключом, не приводит к ошибке, а возвращает специальный объект None. Он используется всегда, когда необходимо указать, что объект отсутствует (в какой-то мере он аналогичен null в C). Если передать методу get второй аргумент - значение по умолчанию, то будет возвращаться это значение, а не None.
End of explanation
d = {}
d
d['zero'] = 0
d
d['one'] = 1
d
Explanation: Словари обычно строят последовательно: начинают с пустого словаря, а затем добавляют ключи со значениями.
End of explanation
d = {i: i ** 2 for i in range(5)}
d
Explanation: А это генератор словаря (dictionary comprehension).
End of explanation
d = {}
d[0, 0] = 1
d[0, 1] = 0
d[1, 0] = 0
d[1, 1] = -1
d
d[0, 0] + d[1, 1]
Explanation: Ключами могут быть любые неизменяемые объекты, например, целые числа, строки, кортежи.
End of explanation
d = {'one': 1, 'two': 2, 'three': 3}
for x in d:
    print(x, '  ', d[x])
Explanation: Словари, подобно спискам, можно использовать в for циклах. Перебираются имеющиеся в словаре ключи (в каком-то непредсказуемом порядке).
End of explanation
d.keys(), d.values(), d.items()
for x in sorted(d.keys()):
    print(x, '  ', d[x])
for x, y in d.items():
    print(x, '  ', y)
del x, y
Explanation: Метод keys возвращает список ключей, метод values - список соответствующих значений (в том же порядке), а метод items - список пар (ключ,значение). Точнее говоря, это не списки, а некоторые объекты, которые можно использовать в for циклах или превратить в списки функцией list. Если хочется написать цикл по упорядоченному списку ключей, то можно использовать sorted(d.keys)).
End of explanation
bool(False), bool(True)
bool(None)
bool(0), bool(123)
bool(''), bool(' ')
bool([]), bool([0])
bool(set()), bool({0})
bool({}), bool({0: 0})
Explanation: Что есть истина? И что есть ложь? Подойдём к этому философскому вопросу экспериментально.
End of explanation
def f():
    pass
f
pass
type(f)
r = f()
print(r)
Explanation: На выражения, стоящие в булевых позициях (после if, elif и while), неявно напускается функция bool. Некоторые объекты интерпретируются как False: число 0, пустая строка, пустой список, пустое множество, пустой словарь, None и некоторые другие. Все остальные объекты интерпретируются как True. В операторах if или while очень часто используется список, словарь или что-нибудь подобное, что означает делай что-то если этот список (словарь и т.д.) не пуст.
Заметим, что число с плавающей точкой 0.0 тоже интерпретируется как False. Это использовать категорически не рекомендуется: вычисления с плавающей точкой всегда приближённые, и неизвестно, получите Вы 0.0 или 1.234E-12.
Лучше напишите if abs(x)&lt;epsilon:.
Функции
Это простейшая в мире функция. Она не имеет параметров, ничего не делает и ничего не возвращает. Оператор pass означает "ничего не делай"; он используется там, где синтаксически необходим оператор, а делать ничено не нужно (после if или elif, после def и т.д.).
End of explanation
def f(x):
    return x + 1
f(1), f(1.0)
f('abc')
Explanation: Эта функция более полезна: она имеет параметр и что-то возвращает.
End of explanation
def f(x, a=0, b='b'):
    print(x, '  ', a, '  ', b)
f(1.0)
f(1.0, 1)
f(1.0, b='a')
f(1.0, b='a', a=2)
f(a=2, x=2.0)
Explanation: Если у функции много параметров, то возникает желание вызывать её попроще в наиболее часто встречающихся случаях. Для этого в операторе def можно задать значения некоторых параметров по умолчанию (они должны размещаться в конце списка параметров). При вызове необходимо указать все обязательные параметры (у которых нет значений по умолчанию), а необязательные можно и не указывать. Если при вызове указывать параметры в виде имя=значение, то это можно делать в любом порядке. Это гораздо удобнее, чем вспоминать, является данный параметр восьмым или девятым при вызове какой-нибудь сложной функции. Обратите внимание, что в конструкции имя=значение не ставятся пробелы между символом =.
End of explanation
a = 1
def f():
    a = 2
    return a
f()
a
Explanation: Переменные, использующиеся в функции, являются локальными. Присваивание им не меняет значений глобальных переменных с такими же именами.
End of explanation
def f():
    global a
    a = 2
    return a
f()
a
Explanation: Если в функции нужно использовать какие-нибудь глобальные переменные, их нужно описать как global.
End of explanation
def f(x, l):
    l.append(x)
    return l
l = [1, 2, 3]
f(0, l)
l
Explanation: Пространство имён устанавливает соответствие между именами переменных и объектами - их значениями. Есть пространство имён локальных переменных функции, пространство имён глобальных переменных программы и пространство имён встроенных функций языка питон. Для реализации пространств имён используются словари.
Если функции передаётся в качестве аргумента какой-нибудь изменяемый объект, и функция его изменяет, то это изменение будет видно снаружи после этого вызова. Мы уже обсуждали эту ситуацию, когда две переменные (в данном случае глобальная переменная и параметр функции) указывают на один и тот же изменяемый объект объект.
End of explanation
def f(x, l=[]):
    l.append(x)
    return l
f(0)
f(1)
f(2)
Explanation: Если в качестве значения какого-нибудь параметра по умолчанию используется изменяемый объект, то это может приводить к неожиданным последствиям. В данном случае исполнение определения функции приводит к созданию двух объектов: собственно функции и объекта-списка, первоначально пустого, который используется для инициализации параметра функции при вызове. Функция изменяет этот объект. При следующем вызове он опять используется для инициализации параметра, но его значение уже изменилось.
End of explanation
def f(x, l=None):
    if l is None:
        l = []
    l.append(x)
    return l
f(0)
f(1)
f(2, [0, 1])
Explanation: Чтобы избежать таких сюрпризов, в качестве значений по умолчанию лучше использовать только неизменяемые объекты.
End of explanation
def f(x, *l):
    print(x, '  ', l)
f(0)
f(0, 1)
f(0, 1, 2)
f(0, 1, 2, 3)
Explanation: Эта функция имеет один обязательный параметр плюс произвольное число необязательных. При вызове все такие дополнительные аргументы объединяются в кортеж, который функция может использовать по своему усмотрению.
End of explanation
l=[1, 2]
c=('a', 'b')
f(*l, 0, *c)
Explanation: Звёздочку можно использовать и при вызове функции. Можно заранее построить список (или кортеж) аргументов, а потом вызвать функцию с этими аргументами.
End of explanation
(*l, 0, *c)
[*l, 0, *c]
[*l, 3]
Explanation: Такую распаковку из списков и кортежей можно использовать не только при вызове функции, но и при построении списка или кортежа.
End of explanation
def f(x, y, **d):
    print(x, '  ', y, '  ', d)
f(0, 1, foo=2, bar=3)
Explanation: Эта функция имеет два обязательных параметра плюс произвольное число необязательных ключевых параметров. При вызове они должны задаваться в виде имя=значение. Они собираются в словарь, который функция может использовать по своему усмотрению.
End of explanation
d={'foo': 2, 'bar': 3}
f(0, 1, **d)
d['x'] = 0
d['y'] = 1
f(**d)
Explanation: Двойную звёздочку можно использовать и при вызове функции. Можно заранее построить словарь аргументов, сопоставляющий значения именам параметров, а потом вызвать функцию с этими ключевыми аргументами.
End of explanation
def f(**d):
    return d
f(x=0, y=1, z=2)
Explanation: Вот любопытный способ построить словарь с ключами-строками.
End of explanation
d={0: 'a', 1: 'b'}
{**d, 2: 'c'}
Explanation: Двойную звёздочку можно использовать не только при вызове функции, но и при построении словаря.
End of explanation
d1 = {0: 'a', 1: 'b'}
d2 = {2: 'c', 3: 'd'}
{**d1, **d2}
Explanation: Вот простой способ объединить два словаря.
End of explanation
d2 = {1: 'B', 2: 'C'}
{**d1, 3: 'D', **d2, 3: 'd'}
Explanation: Если один и тот же ключ встречается несколько раз, следующее значение затирает предыдущее.
End of explanation
def f(x, y, *l, **d):
    print(x, '  ', y, '  ', l, '  ', d)
f(0, 1, 2, 3, foo=4, bar=5)
Explanation: Это наиболее общий вид списка параметров функции. Сначала идут обязательные параметры (в данном случае два), затем произвольное число необязательных (при вызове они будут объединены в кортеж), а затем произвольное число ключевых параметров (при вызове они будут объединены в словарь).
End of explanation
def f0(x):
    return x + 2
def f1(x):
    return 2 * x
l = [f0, f1]
l
x = 2.0
n = 1
l[n](x)
Explanation: В питоне функции являются гражданами первого сорта. Они могут присутствовать везде, где допустимы объекты других типов - среди элементов списков, значений в словарях и т.д.
End of explanation
def fib(n):
    '''вычисляет n-е число Фибоначчи'''
    
    assert type(n) is int and n>0
    
    if n <= 2:
        return 1
    
    x, y = 1, 1
    for i in range(n - 2):
        x, y = y, x + y
    
    return y
fib.__doc__
help(fib)
Explanation: Если Вы пишете функцию не для того, чтобы один раз её вызвать и навсегда забыть, то нужна документация, объясняющая, что эта функция делает. Для этого сразу после строчки def пишется строка. Она называется док-строкой, и сохраняется при трансляции исходного текста на питоне в байт-код (в отличие от комментариев, которые при этом отбрасываются). Обычно эта строка заключается в тройные кавычки и занимает несколько строчек. Док-строка доступна как атрибут __doc__ функции, и используется функцией help. Вот пример культурно написанной функции, вычисляющей $n$-е число Фибоначчи.
Для проверки типов аргументов, переданных функции, удобно использовать оператор assert. Если условие в нём истинно, всё в порядке, и он ничего не делает; если же оно ложно, выдаётся сообщение об ошибке.
End of explanation
fib?
[fib(n) for n in range(1, 10)]
fib(-1)
fib(2.0)
Explanation: В jupyter-ноутбуке к документации можно обращаться более удобным способом
End of explanation
x = zip(range(5), range(0, 10, 2))
print(list(x))
Explanation: Некоторые полезные функции
zip скрещивает два массива одной длины
End of explanation
x = map(lambda tmp: tmp ** 2, range(5))
print(list(x))
Explanation: map применяет функию к каждому элементу массива
End of explanation
x = list(zip([7, 3, 4, 4, 5, 3, 9], ['a', 'n', 'n', 'a', 'k', 'n', 'a']))
# сначала сортировка по букве по алфавиту, потом сортировка по убыванию по числу 
x = sorted(x, key=lambda element: (element[1], -element[0]))
print(list(x))
Explanation: sorted --- сортировка
End of explanation
<END_TASK>