Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the min/max in a list by using a lambda or function to get a comparison value from the item?

In Python I want to find the max element in a list using a lambda for comparison.

No success with this code:

# An 'anonymous' object, like JSON object. Use like: Mock(name='Bob', age=30)
class Mock(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

items = [
    Mock(cost=10, quantity=1),
    Mock(cost=15, quantity=3),
    Mock(cost=20, quantity=5),
    Mock(cost=100, quantity=2)
]

index, value = max(items, key=lambda(item) : item.cost * item.quantity)
print('$%d, q=%d' % (value.cost, value.quantity))

I get this error:

    index, value = max(items, key=lambda(item) : item.cost * item.quantity)
TypeError: 'Mock' object is not iterable

How can I implement this correctly?

like image 772
Remigijus Pankevičius Avatar asked Feb 28 '14 14:02

Remigijus Pankevičius


People also ask

How do you find the minimum and maximum value in Python?

Use Python's min() and max() to find smallest and largest values in your data. Call min() and max() with a single iterable or with any number of regular arguments. Use min() and max() with strings and dictionaries.

How do you find the max value in a list in Python?

The max() function prints the largest element in the list.

How do you find the max element in a list?

Short answer: To find the maximal list in a list of lists, you need to make two lists comparable. How? With the key argument of the max() function. The key argument is a function that takes one input (a list) and returns one output (a numerical value).


2 Answers

If you don't need the index, you can use the result directly:

value = max(items, key=lambda(item) : item.cost * item.quantity)
print value.cost, value.quantity

max returns the actual max item, which is a Mock instance. You can't unpack it into two items.

If you really want the index, you can either find it, or modify your search a little bit to decorate the index into the item:

index, value = max(enumerate(items), key=lambda(item): item[1].cost * item[1].quantity)

First, we convert the original list into a second list where each item is a tuple of (index, value). Then, the key also has to change, because instead of item.cost, item is now an (index, MockItem) pair, and so you need to get item[1], then get the attributes. Don't forget to unpack the result into index and value to get both.

like image 76
Corley Brigman Avatar answered Sep 25 '22 07:09

Corley Brigman


This is not the most efficient way but it's easy for anyone reading it to understand. If you have very large lists, let me know and I'll point you to more efficient solutions.

# get the value
max_item = max(items, key=lambda item: item.cost * item.quantity)
# get the index
max_item_index = items.index(max_item)

If you also want the calculated value, then just do a loop to keep it clear:

max_value = max_index = max_item = None
for i, item in enumerate(items):
    value = item.cost * item.quantity
    if (max_value is None) or (value > max_value):
        max_value = value
        max_index = i
        max_item = item

if max_value is not None:
    print max_index, max_value, max_item        
like image 45
KobeJohn Avatar answered Sep 25 '22 07:09

KobeJohn