Разница между списочным и 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 шт):

Автор решения: MarianD

Потому, что эта программа выводит 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))
→ Ссылка
Автор решения: MaxU

потому что вы при поиске превращаете все числа в 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
→ Ссылка