# selection_sort.py

def min_index(b, i, n):
    """return index of min item in b[i..n-1]. Pre: i <= n."""
    j = i
    k = i + 1
    # inv: b[j] is min of b[i..k-1]
    while k < n:
        j = k if b[k] < b[j] else j
        k += 1
    # post: b[j] is min of b[i..n-1]
    return j
    
def selection_sort(b):
    """Sort list b in place."""
    n = len(b)
    i = 0
    # inv: b[0..i-1] sorted;
    #      b[i..n-1] >= b[0..i-1]
    while i < n:
        j = min_index(b, i, n)
        # b[j] is min item in b[i..n-1]
        b[i], b[j] = b[j], b[i]
        i += 1
    # post: b[0..n-1] sorted

def selection_sort2(b):
    """Sort list b in place."""
    n = len(b)
    i = 0
    # inv: b[0..i-1] sorted;
    #      b[i..n-1] >= b[0..i-1]
    while i < n:
        j = i
        k = i + 1
        # inv (inner): b[j] is min of b[i..k-1]
        while k < n:
            j = k if b[k] < b[j] else j
            k += 1
        # post (inner): b[j] is min of b[i..n-1]
        b[i], b[j] = b[j], b[i]
        i += 1
    # post: b[0..n-1] sorted

def selection_sort3(b):
    """Sort list b in place."""
    n = len(b)
    # inv: b[0..i-1] sorted;
    #      b[i..n-1] >= b[0..i-1]
    for i in range(n):
        j = i
        # inv (inner): b[j] is min of b[i..k-1]
        for k in range(i + 1, n):
            j = k if b[k] < b[j] else j
        # post (inner): b[j] is min of b[i..n-1]
        b[i], b[j] = b[j], b[i]
    # post: b[0..n-1] sorted

if __name__ == '__main__':
    for sort_fn in [selection_sort, selection_sort2, selection_sort3]:
        for x in [[], [2], [1,2], [2,1], [2,4,3,7,5,9,2,1]]:
            y = x[:]
            y.sort()
            z = x[:]
            sort_fn(z)
            assert z == y, str(x) + ' -> ' + str(z) + ' != ' + str(y)