Помогите разобраться с решением задачи Python
Условие:
Дан текст на русском языке. Посчитайте, сколько раз встречается в тексте каждое слово.
Слово — это последовательность русских букв. Кроме слов, в тексте могут присутствовать пробелы и знаки препинания («,», «.», «!», «?», «:» и «;»). Других символов в тексте нет.
Слова необходимо сравнивать с точностью до регистра. То есть «Привет» и «привет» — это одно и то же слово, а вот «рыба», «рыбы» и «рыбу» — три разных.
Ввод:
В первой строчке задано одно целое число N (1 ≤ N ≤ 1000) — количество строк в тексте. В следующих N строках приведён сам русский текст. Текст состоит из русских букв, пробелов и знаков препинания: «,», «.», «!», «?», «:» и «;». Длина текста не превышает 100 000 символов.
Вывод: Выведите слова исходного текста, упорядоченные по убыванию количества их попаданий в текст. В случае, если два слова встречаются в тексте одинаковое количество раз, выведите их в лексикографическом порядке.
Каждое слово нужно вывести в отдельной строке. Первая буква слова должна быть заглавной (даже если она не была заглавной в исходном тексте), остальные — строчными.
Пример:
Ввод:
2
Ехал Грека через реку. Видит Грека в реке рак.
Сунул Грека руку в реку, рак за руку Греку цап.
Вывод:
Грека
В
Рак
Реку
Руку
Видит
Греку
Ехал
За
Реке
Сунул
Цап
Через
У меня даже получилось решить задачу, но не без помощи, мне подсказали использовать непонятную мне функцию:
words_dict = {}
sentences1 = [input().split() for i in range(int(input()))]
sentences = [j.strip('!?:;,.').capitalize() for i in sentences1 for j in i]
for i in sentences:
words_dict[i] = words_dict[i] + 1 if i in words_dict else 1
for word, qwerty in sorted(words_dict.items(), key=lambda x: (-x[1], x[0])): # вот тут непонятно key=lambda x: (-x[1], x[0])
print(word.capitalize())
На строке 6 в конце мне не до конца понятно, как работает выделенная функция, а именно, что она делает.
P.S. Заранее спасибо!
Ответы (2 шт):
words_dict.items() - это список значений вашего словаря. Он имеет вид:
dict_items([('Ехал', 1), ('Грека', 3), ('Через', 1), ('Реку', 2), ('Видит', 1), ('В', 2), ('Реке', 1), ('Рак', 2), ('Сунул', 1), ('Руку', 2), ('За', 1), ('Греку', 1), ('Цап', 1)])
Зная это, можно дать пояснение к сортировке:
# Отсортированный words_dict.items(),
# где сначала в обратном порядке производится сортировка по x[1], т.е. количеству,
# а потом - внутри секций в прямом порядке по x[0], т.е. по самим словам
sorted(words_dict.items(), key = lambda x: (-x[1], x[0]))
Параметр key в функции sorted указывает, по чём именно сортируется итерируемый объект.
Более простой пример: имея список кортежей [(1, 2), (-2, 3), (5, -10)], можно с помощью key отсортировать его, например, по нулевому элементу:
# x - это сами элементы списка, а сортируем мы по x[0]
>>> sorted([(1, 2), (-2, 3), (5, -10)], key = lambda x: x[0])
[(-2, 3), (1, 2), (5, -10)]
Лямбда функция - это вариант безымянной функции, состоящей из одного выражения / команды. Является синтаксическим сахаром и всегда может быть заменена обычной функцией (см. пример ниже). Часто применяется для сокращения кода, в тех местах где нужно передавать функцию в качестве параметра, например в качестве параметра key во встроенных функциях: min(), max(), sorted(), etc..
Пример замены обычной однокомандной функции лямбда функцией:
In [38]: def revers(s):
...: return s[::-1]
...:
In [39]: revers("AbCdE")
Out[39]: 'EdCbA'
In [40]: (lambda x: x[::-1])("AbCdE")
Out[40]: 'EdCbA'
Конечно выглядит это ужасно и никто не применяет лямда функции таким образом. Применение лямбда функций удобно и оправдано в том случае, когда на нужно передавать функцию в качестве аргумента другой функции или объекту класса.
Пример с сортировкой: - допустим надо надо отсортировать список кортежей сначала по второму элементу в убывающем порядке, а потом по первому элементу в возрастающем (как в вашем предыдущем вопросе):
In [42]: items = [(1,10), (1,20), (2,10), (2,20)]
In [43]: def f(x):
...: return (-x[1], x[0])
...:
In [44]: sorted(items, key=f)
Out[44]: [(1, 20), (2, 20), (1, 10), (2, 10)]
того же эффекта можно добиться, не создавая именованной функции:
In [45]: sorted(items, key=lambda x: (-x[1], x[0]))
Out[45]: [(1, 20), (2, 20), (1, 10), (2, 10)]
Ответ на вопрос из комментария:
Как сортировать строки в обратном алфавитном порядке?
в том случае когда порядок сортировки всегда один - можно воспользоваться параметром sorted(..., reverse=True)
In [48]: sorted(res.items(), key=lambda x: (x[1], x[0]), reverse=True)
Out[48]:
[('грека', 3),
('руку', 2),
('в', 2),
('через', 1),
('цап', 1),
('сунул', 1),
('реку.', 1),
('реку,', 1),
('реке', 1),
('рак.', 1),
('рак', 1),
('за', 1),
('ехал', 1),
('греку', 1),
('видит', 1)]