简体   繁体   中英

Why does min() in Python return the key when a lambda is used on dictionaries?

I am studying the Python Cookbook, 3rd edition. I encountered the code below:

prices = {'ACME': 45.23,'AAPL': 612.78,'IBM': 205.55,'HPQ': 37.20,'FB': 10.75}

min(prices, key=lambda k: prices[k])

I tested this on Python 3.6.0, and it returns 'FB'.

My understanding is that every key from the prices dictionary is sent to the lambda as parameter k and then the lambda returns the value associated with key k in the prices dictionary. So after iterating through all the keys, a list of values is returned which is used as an argument to the min function which finally returns the minimum value (in this case 10.75) in the dictionary.

But when I ran the code, the program printed out the key (in this case 'FB'). Where am I wrong?

I have gone through the documentation. It said min returns the smallest item in an iterable. I know min processes the keys and not the values. I just don't understand how it returns the key when the lambda returns a list of values. Help me please.

EDIT : Sorry for the edit. I am trying to find the key of the smallest value in the dictionary. The above code works perfectly but I don't know how it works.

You are correct that the lambda function you defined will be applied to all the keys, however that does not mean that min will return whatever your lambda function may return.

Perhaps it's helpful to spell out the line

min(prices, key=lambda k: prices[k])

in words:

"Find the minimum of the iterable prices (the dictionary keys 1 ), as if each key k had the value prices[k] ."

If you want the associated value, you can use the returned key to access prices

>>> prices[min(prices, key=lambda k: prices[k])]
>>> 10.75

or much shorter:

>>> min(prices.values())
>>> 10.75

1 Because a dictionary is an iterable of keys ( list(prices) gives a list of keys).

why min() in python returns key when lambda is used on dictionaries

Because iterating dictionaries iterates over the keys in arbitrary order. The key parameter is NOT a map parameter.

If you want the minimum value, then take min(prices.items()) min(prices.values()) .

When you iterate through a dictionary (as you are doing implicitly with min() ), it uses the keys. min(prices) is equivalent to min(prices.keys()) . So min() iterates through each of the KEYS in the dictionary, and uses the lambda function to compare them. It returns one of the items in what it is iterating over - so one of the keys.

If you want the items instead, you can use min(prices.items()) , no key needed.

If you want both, I would just use what you have an get the price with the returned key.

The thing you supply as key is merely used to sort the iterable you give it - in your case all the keys of the dictionary - you get "the one" returned that is lowest according to your key-definition .

Example:

data = ["a","bb","ccc","dddd"]

print( min( data, key = lambda x: -len(x))) # get the min value by negative length ascending

Prints:

dddd

because the elements of the list got evaluated according to theire respective negative length:

['a', 'bb', 'ccc', 'dddd']  # iterable
[ -1,  -2 ,   -3,     -4 ]  # the key-result

and the minimal ones from the iterable was returned: 'dddd'

If you want both the key and the value, you can use:

>>> min(prices.items(), key=lambda kv: kv[1])
('FB', 10.75)

min returns the smallest item of an iterable. To decide what elements are smaller, it uses the key. Here, you're asking for the minimum of prices , so it returns the smallest element of that iterable. The key just tells min to use that key in deciding which items of the iterable are smaller; min still uses the values of the iterable, not the key applied to the values, as the minimum to return. Imagine if someone says "Tell me what country is largest by population". The correct answer is "China", not 1.386 billion. 1.386 billion is the value used to decide that China is "largest", not the thing that is largest. When you write min(iterable, key=key) , you are asking for the smallest of iterable by key , not the smallest key . Basically, min is equivalent to the following:

 def min(iterable, key = lambda x:x):
      cur_min = iterable.first
      for item in iterable:
            if key(item)<key(cur_min):
                 cur_min = item
     return cur_min

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM