How can I get the minimum and the maximum element of a list in python
Question: If a have a list like:

    
    
    l = [1,2,3,4,5]
    

and I want to have at the end

    
    
    min = 1   
    max = 5
    

WITHOUT `min(l)` and `max(l)`.


Answer: Loop over the list and test each item against the minimum and maximum found so
far. `float('inf')` and `float('-inf')` (infinity and negative infinity) are
good starting points to simplify the logic:

    
    
    minimum = float('inf')
    maximum = float('-inf')
    for item in l:
        if item < minimum:
            minimum = item
        if item > maximum:
            maximum = item
    

Alternatively, start with the first element and only loop over the rest; I use
[`itertools.islice()`](http://docs.python.org/2/library/itertools.html#itertools.islice)
here to avoid creating a copy of a potentially large list:

    
    
    from itertools import islice
    
    minimum = maximum = l[0]
    for item in islice(l, 1, None):
        if item < minimum:
            minimum = item
        if item > maximum:
            maximum = item
    

or turn the list into an iterable first:

    
    
    iterl = iter(l)
    minimum = maximum = next(iterl)
    for item in iterl:
        if item < minimum:
            minimum = item
        if item > maximum:
            maximum = item
    

Timing comparisons with a larger, random list:

    
    
    >>> from random import shuffle
    >>> l = range(1000)
    >>> shuffle(l)
    >>> from timeit import timeit
    >>> def straight_min_max(l):
    ...     return min(l), max(l)
    ... 
    >>> def sorted_min_max(l):
    ...     s = sorted(l)
    ...     return s[0], s[-1]
    ... 
    >>> def looping(l):
    ...     l = iter(l)
    ...     min = max = next(l)
    ...     for i in l:
    ...         if i < min: min = i
    ...         if i > max: max = i
    ...     return min, max
    ... 
    >>> timeit('f(l)', 'from __main__ import straight_min_max as f, l', number=10000)
    0.5266690254211426
    >>> timeit('f(l)', 'from __main__ import sorted_min_max as f, l', number=10000)
    2.162343978881836
    >>> timeit('f(l)', 'from __main__ import looping as f, l', number=10000)
    1.1799919605255127
    

So even for lists of 1000 elements, the `min()` and `max()` functions are
fastest. Sorting is slowest here. The sorting version can be faster if you
allow for _in-place_ sorting, but then you'd need to generate a new random
list for each timed run as well.

Moving to a million items (and only 10 tests per timed run), we see:

    
    
    >>> timeit('f(l)', 'from __main__ import straight_min_max as f, l', number=10)
    1.6176080703735352
    >>> timeit('f(l)', 'from __main__ import sorted_min_max as f, l', number=10)
    6.310506105422974
    >>> timeit('f(l)', 'from __main__ import looping as f, l', number=10)
    1.7502741813659668
    

Last but not least, using a million items and `l.sort()` instead of
`sorted()`:

    
    
    >>> def sorted_min_max(l):
    ...     l.sort()
    ...     return l[0], l[-1]
    ... 
    >>> l = range(1000000)
    >>> shuffle(l)
    >>> timeit('f(l[:])', 'from __main__ import straight_min_max as f, l', number=10)
    1.8858389854431152
    >>> timeit('f(l[:])', 'from __main__ import sorted_min_max as f, l', number=10)
    8.408858060836792
    >>> timeit('f(l[:])', 'from __main__ import looping as f, l', number=10)
    2.003532886505127
    

Note the `l[:]`; we give each test run a copy of the list.

Conclusion: even for large lists, you are better off using the `min()` and
`max()` functions anyway. Nothing beats a good C loop. But if you have to
forgo those functions, the straight loop is the next better option.

