min() & max() in Python
The builtin max() and min() functions are used to find out the maximum & minimum valued elements of the given iterable. Actually, they have a couple of complications behind this simple facade. In this article, I'll highlight these nuance details. I'll demonstrate using the max() function, you can map the points made on to min() function as they work similarly.
Basic Example
Let's look at a few examples of max() in action.
>>> max( [1, 2, 3, 4] ) 4 >>> max( (1, 2, 3, 4) ) 4 >>> max( ['a', 'b', 'c'] ) 'c' >>> max( ['apple', 'attic', 'aardvark'] ) 'attic'
Documentation
To set the pretext of our further discussion, let's look at what the help() function has to say about the max() function.
>>> help(max) Help on built-in function max in module builtins: max(...) max(iterable, *[, default=obj, key=func]) -> value max(arg1, arg2, *args, *[, key=func]) -> value With a single iterable argument, return its biggest item. The default keyword-only argument specifies an object to return if the provided iterable is empty. With two or more arguments, return the largest argument.
Two forms of the max() function
So, according to the documentation, there are two implementations of the max() function i.e. there are two ways in which it can be called.
- With a single iterable: In this case, the max() returns the maximum valued element of the iterable supplied. This form takes two optional keyword arguments: default & key. We'll discuss these in subsequent sections.
- With more than one iterable: In this case, the max() returns the maximum valued iterable, so to speak, of the ones provided. The max() compares corresponding elements of the iterables, and at the first point of differentiation, returns the larhger of the iterable. This form takes only one optional keyword argument: key.
>>> max( [1, 2] ) 2 >>> max ( [1, 2], [1, 3], [1, 4] ) [1, 4] # Since strings are also iterables, you can compare strings using the second form as well. >>> max( 'a', 'b', 'c' ) 'c' >>> max( 'apple', 'attic', 'aardvark' ) 'attic' # Corresponding elements at 2nd position: t > p > a
How does Python compare elements?
As I said, Python compares corresponding elements of the iterables. But how DOES Python compare these corresponding elements? The answer is, that it uses the builtin ord() function to compare each individual element. The ord() function returns the Unicode value of the character supplied to it. It is inverse of builtin chr() function which returns the character in the Unicode character set, denoted by the number provided to it.
>>> ord('a') 97 >>> ord('b') 98 >>> chr(98) 'b' >>> chr(97) 'a' >>> unicodeMappings = {} >>> for index in range(33, 127): unicodeMappings.update({index:chr(index)}) >>> print( '\t'.join(['{0}: {1}'.format(index, character) for index,character in unicodeMappings.items() ] ) ) 33: ! 34: " 35: # 36: $ 37: % 38: & 39: ' 40: ( 41: ) 42: * 43: + 44: , 45: - 46: . 47: / 48: 0 49: 1 50: 2 51: 3 52: 4 53: 5 54: 6 55: 7 56: 8 57: 9 58: : 59: ; 60: < 61: = 62: > 63: ? 64: @ 65: A 66: B 67: C 68: D 69: E 70: F 71: G 72: H 73: I 74: J 75: K 76: L 77: M 78: N 79: O 80: P 81: Q 82: R 83: S 84: T 85: U 86: V 87: W 88: X 89: Y 90: Z 91: [ 92: \ 93: ] 94: ^ 95: _ 96: ` 97: a 98: b 99: c 100: d 101: e 102: f 103: g 104: h 105: i 106: j 107: k 108: l 109: m 110: n 111: o 112: p 113: q 114: r 115: s 116: t 117: u 118: v 119: w 120: x 121: y 122: z 123: { 124: | 125: } 126: ~ >>> max( 'apple', 'attic', 'aardvark' ) 'attic' # Corresponding elements at 2nd position: ord(t) > ord(p) > ord(a)
The optional keyword argument 'default' in first form
The default keyword argument is used to tell the max() function what it should return in case the iterable provided to it is empty.
>>> max( [ ], default = 10) 10
The optional keyword argument 'key'
The optional keyword argument key takes a function name in its keyword form i.e. without parentheses. The function so mentioned must be capable of taking each element of the provided iterable object, and it must be capable of returning a comparable value, such as ord(), sum() etc. The order of the resultant list is decided on the basis of values returned by this function. The default value for the key argument is None, meaning that the elements are compared directly i.e. using the ord() function on corresponding elements of entries.
>>> max( [ (1,5), (2,3), (3,4) ] ) (3, 4) # ord('1') < ord('2') < ord('3') >>> max( [ (1,5), (2,3), (3,4) ], key = sum ) (3, 4) # 2 + 3 < 1 + 5 < 3 + 4 # Providing a custom function to the 'key' argument >>> def product(iterableOfTwo): a, b = iterableOfTwo return a * b >>> max( (1, 15), (2, 3), (3, 4), key = product ) (1, 15) # 1 * 15 > 3 * 4 > 2 * 3
Trying to find the better of Apples & Oranges
The max() does not do well while trying to compare two different types of sequences, list and tuple for instance.
>>> max( (1, 2), [1, 3] ) Traceback (most recent call last): max( (1, 2), [1, 3] ) TypeError: unorderable types: list() > tuple()
That's it. This is all there is to the builtin max() function. Since the min() function operates the same way, everything we have discussed applies to it too.
Cheerio!