python max function using 'key' and lambda expression
lambda
is an anonymous function, it is equivalent to:
def func(p):
return p.totalScore
Now max
becomes:
max(players, key=func)
But as def
statements are compound statements they can't be used where an expression is required, that's why sometimes lambda
's are used.
Note that lambda
is equivalent to what you'd put in a return statement of a def
. Thus, you can't use statements inside a lambda
, only expressions are allowed.
What does max
do?
max(a, b, c, ...[, key=func]) -> value
With a single iterable argument, return its largest item. With two or
more arguments, return the largest argument.
So, it simply returns the object that is the largest.
How does key
work?
By default in Python 2 key
compares items based on a set of rules based on the type of the objects (for example a string is always greater than an integer).
To modify the object before comparison, or to compare based on a particular attribute/index, you've to use the key
argument.
Example 1:
A simple example, suppose you have a list of numbers in string form, but you want to compare those items by their integer value.
>>> lis = ['1', '100', '111', '2']
Here max
compares the items using their original values (strings are compared lexicographically so you'd get '2'
as output) :
>>> max(lis)
'2'
To compare the items by their integer value use key
with a simple lambda
:
>>> max(lis, key=lambda x:int(x)) # compare `int` version of each item
'111'
Example 2: Applying max
to a list of tuples.
>>> lis = [(1,'a'), (3,'c'), (4,'e'), (-1,'z')]
By default max
will compare the items by the first index. If the first index is the same then it'll compare the second index. As in my example, all items have a unique first index, so you'd get this as the answer:
>>> max(lis)
(4, 'e')
But, what if you wanted to compare each item by the value at index 1? Simple: use lambda
:
>>> max(lis, key = lambda x: x[1])
(-1, 'z')
Comparing items in an iterable that contains objects of different type:
List with mixed items:
lis = ['1','100','111','2', 2, 2.57]
In Python 2 it is possible to compare items of two different types:
>>> max(lis) # works in Python 2
'2'
>>> max(lis, key=lambda x: int(x)) # compare integer version of each item
'111'
But in Python 3 you can't do that any more:
>>> lis = ['1', '100', '111', '2', 2, 2.57]
>>> max(lis)
Traceback (most recent call last):
File "<ipython-input-2-0ce0a02693e4>", line 1, in <module>
max(lis)
TypeError: unorderable types: int() > str()
But this works, as we are comparing integer version of each object:
>>> max(lis, key=lambda x: int(x)) # or simply `max(lis, key=int)`
'111'
Is it possible to have more than one key/lambda for python's max/min functions?
Finding the dictionary with max profit and the index works without copying the profit value as first element in a list
. I slightly modified the dictionaries.
d = [{'profit': 3, 'buy_idx': 0, 'sell_idx': 1},
{'profit': 0, 'buy_idx': None, 'sell_idx': None},
{'profit': 7, 'buy_idx': 0, 'sell_idx': 2}]
index, maxdict = max(enumerate(d), key=lambda x: x[1]['profit'])
print(f'max profit in {maxdict} at index {index}')
Output
max profit in {'profit': 7, 'buy_idx': 0, 'sell_idx': 2} at index 2
how does Lambda work in python with max function?
From https://www.programiz.com/python-programming/methods/built-in/min:
- min(iterable, *iterables[, key, default])
- iterable - sequence (tuple, string), collection (set, dictionary) or an iterator object whose smallest element is to be found
- *iterables (Optional) - any number of iterables whose smallest is to be found
- key (Optional) - key function where the iterables are passed and comparison is performed based on its return value
- default (Optional) - default value if the given iterable is empty
The call min(stocks, key= lambda x:stocks[x])
is finding the smallest element in stocks
, by comparing the results of the function lambda x:stocks[x]
, which is just an anonymous function that returns the value of the stock for a given key. So the call to min
returns the stock with the smallest value.
See also Get the key corresponding to the minimum value within a dictionary and http://www.aroseartist.com/python-dictionary-max-min/
find max using key and lambda in python
If you pass a dictionary to max
, it iterates over the dictionary keys (which is a list of strings here), and since you've specified a comparator function, the comparison is now done on x[1]
(in the first line) which happens to be the second character of each key, and x[0]
(in the second line) which happens to be the first character of each key.
So, for example, you have a list of keys:
['forward', 'zone', 'right', 'left']
Note that this list could be returned in any order, because dictionaries have no ordering. Now, the basis for choosing the max is the 2nd character, so you choose based on:
['f o rward', 'z o ne', 'r i ght', 'l e ft']
And it just so happens that, for your CPython implementation, forward
is returned before zone
(although either one could have been returned, depending on the order in which keys were returned from the dictionary).
How to convert a lambda function to a key argument for the max() function?
This function counts the amount for each element and returns the element with most elements. The lambda
is not necessary, since name_list.count
already is a function:
def most_appear(name_list):
return max(name_list, key=name_list.count)
max(*args, key = ... ). How to modify key to get just certain values?
Yes, you CAN do this by a single line with max
function. I explain it below.
And ALSO there is a better way than list comprehension that I explained in the end.
Reason of your problem:
This is how the max function works if you have provided the key parameter. It will loop through the values of the list and then it applies the lambda function (named key
) on each value. So all of the values will be mapped to the result of the lambda function. Then it performs the max
function on these results.
So when you have key=lambda x: x<0
this will return True
or False
as x<0
is a boolean expression. So the result list would be like [False, False, False, True, True, True]
. These False
and True
values are processed as 0
and 1
values for the max function.
The max
function gets [0, 0, 0, 1, 1, 1]
and it finds the first one that is the maximum number in the list (number 1) that is the first 1
in the list that corresponds to number -5 in the original list.
Solution:
There are multiple ways to find the maximum negative number like using a for loop or list comprehension or even combining filter
and max
. But, to understand the max
function and it's parameters better I show you the way you can do the thing you want (find the maximum negative number) by the max
function.
max(my_list, key = lambda x: min(my_list) if x>=0 else x)
This code will find the maximum negative number.
How does this code work?
The provided lambda expression will map all the number as this:
If the number is positive we replace it's value for the max function as the minimum number so it will never be chosen as the maximum negative number. (We could do this by removing all the negative number by filter
but I decided to do all the job just with lambda to show you the way.)
If the number is negative it will keep it's own value. So for your example that the list is my_list = [2, 3, 4, -5, -2, -1]
it will create [-5, -5, -5, -5, -2, -1]
and then it will perform the max
function on this list that it will find the -1
number that is what you want.
I wish it could help you understand how to find the maximum negative number just by the max
function and the way maximum function works.
NOTE: This code is not optimal. Because every time it computes the minimum value. This code is only for learning purposes.
Best way to do this
I believe a better code is this:
max((num for num in my_list if num<0))
Note that this is not list comprehension. It is better than list comprehension. Instead it creates a generator that only process one value at a time. This is better that list comprehension because list comprehension creates the whole list at once and then send it to the max function. But this code process each value at a time and don't fill the memory with a big list. So this is more efficient.
Problems with understanding this use of lambda with max
The function returned by the following lambda
expression:
lambda i: (isinstance(i, int), i)
is the same as the function that is assigned to f
by the following def
statement:
def f(i):
return (isinstance(i, int), i)
The return value of the function (which takes i
as an argument) is a tuple where the first element is a bool
indicating whether i
is an int
, and the second element is i
itself:
>>> f(5)
(True, 5)
>>> f("foo")
(False, 'foo')
Tuples are compared in order of their elements, so in the context of the max
call, this means that you'll get the largest int
value (because True
is "greater than" False
), and will get the largest of whatever other type of value you have only if there are no int
values.
Related Topics
How to Read Text from the Clipboard
Fixed Digits After Decimal with F-Strings
Removing Item from List - During Iteration - What's Wrong with This Idiom
How to Run Multiple While Loops at a Time in Pygame
Split Cell into Multiple Rows in Pandas Dataframe
Sum a List of Numbers in Python
How to Correctly Clean Up a Python Object
Can You Monkey Patch Methods on Core Types in Python
Why Can't Non-Default Arguments Follow Default Arguments
How to Fix Overlapping Annotations/Text
Setup Script Exited with Error: Command 'X86_64-Linux-Gnu-Gcc' Failed with Exit Status 1
Groupby Results to Dictionary of Lists
Python Garbage Collector Documentation
Taking Multiple Integers on the Same Line as Input from the User in Python