Python Max Function Using 'Key' and Lambda Expression

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:

  1. 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



Leave a reply



Submit