Remigijus Pankevičius
Remigijus Pankevičius

Reputation: 1132

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?

Upvotes: 6

Views: 9945

Answers (2)

Corley Brigman
Corley Brigman

Reputation: 12391

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.

Upvotes: 8

KobeJohn
KobeJohn

Reputation: 7545

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        

Upvotes: 2

Related Questions