I know a bit about how key argument is used in python max(). max(("pyth", "lua", "ruby"), key=len) will return pyth and ruby. However, max((31, 13, 11), key=lambda x: sum(int(i) for i in str(x))) will only give me 31 (13 should be returned as well), or max((13, 31, 11), key=lambda x: sum(int(i) for i in str(x))) will only give me 13 (31 should be returned as well). Can someone explain this? Many thanks.
3 Answers
Regarding your contention:
max(("pyth", "lua", "ruby"), key=len)will returnpythandruby.
No, it really won't:
>>> max(("pyth", "lua", "ruby"), key=len)
'pyth'
The max functions returns only one value, the maximum value. With default method, it doesn't normally matter since two values of 31 can return either sensibly.
But, if you conflate visibly different items so that they have the same "value", you'll be able to tell the difference when printing.
By the way, you always get the first one found during iteration, as per the docs (my emphasis in the final paragraph, which is the paragraph making it clear only one item, and which in the case of duplicates, is returned):
max(iterable, *, key=None)
max(iterable, *, default, key=None)
max(arg1, arg2, *args, key=None)Return the largest item in an iterable or the largest of two or more arguments.
If one positional argument is provided, it should be an iterable. The largest item in the iterable is returned. If two or more positional arguments are provided, the largest of the positional arguments is returned.
There are two optional keyword-only arguments. The
keyargument specifies a one-argument ordering function like that used forlist.sort(). Thedefaultargument specifies an object to return if the provided iterable is empty. If the iterable is empty and default is not provided, aValueErroris raised.If multiple items are maximal, the function returns the first one encountered. This is consistent with other sort-stability preserving tools such as
sorted(iterable, key=keyfunc, reverse=True)[0]andheapq.nlargest(1, iterable, key=keyfunc).
Comments
As max() can only return one value, you'll need a custom function to return a list of all values that equate to the maximum sum of digits.
You could do this:
from functools import cache
v = (31, 13, 11)
@cache
def sum_digits(n): # much faster than converting to strings and slicing
s = 0
while n > 0:
s += n % 10
n //= 10
return s
def getvals(v):
m = sorted(v, key=sum_digits, reverse=True)
result = [m[0]] # effectively the max value
for e in m[1:]:
if sum_digits(e) != sum_digits(m[0]):
break
result.append(e) # has same sum of digits as the max value
return result
print(getvals(v))
Output:
[31, 13]
max(("pyth", "lua", "ruby"), key=len)will NOT returnpythandruby.