Разница между списочным и key (в данном примере)
Скажите, почему в этом примере max и key=lambda x: x % 2 != 0 выводит не максимальный нечетный элемент в списке?
Ввод:
6
100
8
33
45
19
90
Программа:
n = int(input())
k = []
for i in range(n):
num = int(input())
k.append(num)
print(k)
even = max(k, key=lambda x: x % 2 == 0) # то есть максимальный четный элемент списка
odd = max(k, key=lambda x: x % 2 != 0) # максимальный нечетный элемент списка (но выводит 33, вместо 45)
print(even)
print(odd)
Должно получиться 100 и 45, но выводит 100 и 33. Почему?
Ответы (2 шт):
Потому, что эта программа выводит 2 числа:
- первое из четных чисел,
- первое из нечетных чисел.
Объяснение:
Выражение key=lambda x: x % 2 == 0 значит, что для всякого числа xсначала вычислится остаток после деления двумя (x % 2), затем он сравнивается с нулем (== 0), чем получится True для четных и False для нечетных чисел.
Сравнивая эти значения (True и False), True более False, значит, максимом будет первое четное число.
(Подобным способом для выражения key=lambda x: x % 2 != 0 — здесь «выигрывает» первое нечетное число.)
Исправление:
Вы не хотите изменить ключ для вычисления максима, вы хотите фильтровать применением этой ламбда-функции — значит, правильные команды будут
even = max(filter(lambda x: x % 2 == 0, k))
odd = max(filter(lambda x: x % 2 != 0, k))
потому что вы при поиске превращаете все числа в True / False, которые в Python представлены числами 1 / 0, и, соответственно, всегда получаете первое число удовлетворяющее условию (True).
Т.е. в случае с max(k, key=lambda x: x % 2 == 0) вы ищете максимум в следующем списке по второму элементу кортежа:
In [77]: print([(x, x%2==0) for x in k])
[(6, True), (100, True), (8, True), (33, False), (45, False), (19, False), (90, True)]
Первое True (четное) - 6 - его вы и получаете, тоже самое с нечетными - вы получаете первое нечетное из списка - 33
Можно слегка исправить ваше решение:
In [71]: from math import inf
In [72]: max(k, key=lambda x: x if x % 2 == 0 else -inf)
Out[72]: 100
для нечетных:
In [73]: max(k, key=lambda x: x if x % 2 != 0 else -inf)
Out[73]: 45
Но лучше сделать так - это более явная и понятная форма:
In [74]: max(x for x in k if x%2==0)
Out[74]: 100
In [75]: max(x for x in k if x%2!=0)
Out[75]: 45