Why does max behave differently if I pass a lambda

2020-05-10 07:18发布

问题:

I'm trying to understand how the key argument works in the max function, coming from a problem of finding the closest integer to 0 from a list, and using the positive value in case of having the same positive and negative value in the list.

I have found this to be an efficient solution online, given a list of integers x:

print(max(a, key=lambda x: (-abs(x), x), default=0))

This returns a single integer, where I would expect to return a tuple, given that the lambda will transform every element of x into a tuple, then I did this:

b = list(map(lambda x: (-abs(x), x), a))
max(b)

And this second example returns a tuple. Why does the first one return a single elements when it is comparing tuples generated by the lambda?

回答1:

You are comparing two different things.

For your first case, if we look at the docs: https://docs.python.org/3/library/functions.html#max

max(arg1, arg2, *args[, key])
Return the largest item in an iterable or the largest of two or more arguments. The key argument specifies a one-argument ordering function like that used for list.sort().

Which means that the key lambda x: (-abs(x), x) is a ordering function, which means that for every x in iterable a, (-abs(x), x) is evaluated and is used to order the items for finding out the maximum element of the iterator, and according to that ordering, 1 is the maximum element

In [24]: a = [1,4,6,-8,-10] 

In [40]: print(max(a, key=lambda x: (-abs(x), x), default=0))                                                                                                                       
1

For the second case, if we look at the docs: https://docs.python.org/3/library/functions.html#map

map(function, iterable, ...)
Return an iterator that applies function to every item of iterable, yielding the results

Which means that the function lambda x: (-abs(x), x) is applied to every element x of a, so we get back (-abs(x), x) for every x, and the max is applied on the updated iterator, which is the largest tuple (-1,1)

In [25]: b = list(map(lambda x: (-abs(x), x), a))  

In [26]: b                                                                                                                                                                          
Out[26]: [(-1, 1), (-4, 4), (-6, 6), (-8, -8), (-10, -10)]

In [27]: max(b)                                                                                                                                                                     
Out[27]: (-1, 1)