Как достать максимальную и минимальную пару из класса Counter() используя сортировку?
Есть Counter с таким содержимым:
Counter({'Все везде и сразу': 4, 'На Западном фронте без перемен': 2, 'Топ Ган: Мэверик': 2, 'Аватар: Путь воды': 1})
Надо достать это:
Все везде и сразу, 4
Аватар: Путь воды, 1
я сделал по первому и последнему индексу приведя к листу, но интересно как через sorted() это сделать.
Спасибо!
Ответы (3 шт):
sorted
не нужен. c.items()
возвращает пары (ключ, значение), key=lambda i: i[1]
отбирает значения из пар, min
и max
по значениям выбирают "минимальную" и "максимальную" пары.
Для максимальных значений есть специальный метод collections.Counter.most_common
.
import collections
c = collections.Counter({
'Все везде и сразу': 4,
'На Западном фронте без перемен': 2,
'Топ Ган: Мэверик': 2,
'Аватар: Путь воды': 1
})
print(min(c.items(), key=lambda i: i[1]))
print(max(c.items(), key=lambda i: i[1]))
print(c.most_common(1)[0])
$ python counter.py ('Аватар: Путь воды', 1) ('Все везде и сразу', 4) ('Все везде и сразу', 4)
P.S. c.most_common()[-1]
вернёт самый непопулярный фильм. Но вызов most_common
без параметра приводит к сортировке, чего лучше избегать (время и память не бесплатны).
P.P.S. Что будет если самых популярных фильмов больше одного? Текущее решение вернёт какой-то один. А надо бы возвращать все самые пулярные:
import collections
c = collections.Counter({
'Все везде и сразу': 4,
'Ещё один лидер проката': 4,
'На Западном фронте без перемен': 2,
'Топ Ган: Мэверик': 2,
'Аватар: Путь воды': 1,
'Ещё один неудачник проката': 1
})
min_value = min(c.values())
print(*filter(lambda i: i[1] == min_value, c.items()))
max_value = max(c.values())
print(*filter(lambda i: i[1] == max_value, c.items()))
$ python counter.py ('Аватар: Путь воды', 1) ('Ещё один неудачник проката', 1) ('Все везде и сразу', 4) ('Ещё один лидер проката', 4)
from collections import Counter
counter = Counter({
'Все везде и сразу': 4,
'На Западном фронте без перемен': 2,
'Топ Ган: Мэверик': 2,
'Аватар: Путь воды': 1
})
Для этого нужно просто сортировать не по ключу в словаре, а по значению. Для этого в функции sorted()
существует аргумент key
.
Сначала превращаем словарь в список, состоящий из кортежей ("key", "value")
.
А затем, через лямбда-функцию выбираем то, по чему мы будем сортировать, то есть последний элемент кортежа:
sorted_pairs = sorted(counter.items(), key=lambda x: x[1])
Соотвественно, пара с наибольшим значением будет первой в списке, с наименьшим - в конце
И тогда получаем:
min_pair, max_pair = sorted_pairs[0], sorted_pairs[-1]
print(*min_pair)
print(*max_pair)
Все везде и сразу 4
Аватар: Путь воды 1
Пара тонких моментов:
- lambda - это очень медленно.
- Метод items() создает в памяти список кортежей с парами ключ-значение для всего содержимого словаря, т.е. фактически дублируем словарь в памяти.
Более эффективный вариант, хотя и не идеальный. Существует вариант еще быстрее, но несколько громоздкий и требует написание функции.
from operator import itemgetter
print(min(iter(c.items()), key=itemgetter(1)))
print(max(iter(c.items()), key=itemgetter(1)))