# some sorts
#import sys
from random import shuffle, randint
from random import randint
#sys.setrecursionlimit(1000000)

# weird function
# check out f.__defaults__
def f(n: int, L: list=[]) -> list:
    L.append(n)
    return L

def select(L):
    """Produce copy of L in sorted order

    >>> select([3, 1, 2])
    [1, 2, 3]
    """
    L1 = L[:]
    for i in range(len(L1)):
        m = min(L1[i:])
        j = L1.index(m,i)
        L1[i], L1[j] = L1[j], L1[i]
    return L1


def quick(L: list) -> list:
    """Produce a sorted version of L

    >>> quick([2, 1, 3])
    [1, 2, 3]
    """
    if len(L) < 2:
        return L[:]
    else:
        # i = randint(0, len(L) - 1)
        i = 0
        return (quick([x for x in L if x < L[i]]) +
                [L[i]] +
                quick([x for x in (L[0:i] + L[i+1:]) if x >= L[i]]))


def merge(L1, L2):
    """return merge of L1 and L2

    >>> merge([1, 3, 5], [2, 4, 6])
    [1, 2, 3, 4, 5, 6]
    >>> merge([1, 2, 3], [0, 4, 5])
    [0, 1, 2, 3, 4, 5]
    >>> merge([0], [1, 2, 3, 4])
    [0, 1, 2, 3, 4]
    """
    L = []
    i1, i2 = 0, 0
#    every slice is a (linear) copy!
#    while L1[i1:] and L2[i2:]:
    while i1 < len(L1) and i2 < len(L2):
        if L1[i1] < L2[i2]:
            L.append(L1[i1])
            i1 += 1
        else:
            L.append(L2[i2])
            i2 += 1
    return L + L1[i1:] + L2[i2:]

def merge_sort(L):
    """Produce copy of L in non-decreasing order

    >>> merge_sort([1, 5, 3, 4, 2])
    [1, 2, 3, 4, 5]
    >>> L = list(range(20))
    >>> shuffle(L)
    >>> merge_sort(L) == list(range(20))
    True
    """
    if len(L) < 2 :
        return L[:]
    else :
        return merge(merge_sort(L[:len(L)//2]), merge_sort(L[len(L)//2:]))

def count_sort(L):
    """silly functional sort.  See radix sort for something serious"""
    count_list = [0, ] * len(L)
    for i in L:
        count_list[i] += 1

    L1 = [] # blank slate!
    for i in range(len(count_list)):
        for j in range(count_list[i]):
            L1.append(i)
    return L1


if __name__== '__main__':
    import doctest
    doctest.testmod()
    from time import time, clock
    from random import shuffle
    L = list(range(10000000))
    shuffle(L)
   #start = time()
   #select(L)
   #print("select sort: {} for {} items".format(time() - start, len(L)))
    #start = time()
    #quick(L)
    #print("quick sort: {} for {} items".format(time() - start, len(L)))
    #start = time()
    #quick(L)
    #print("quick sort: {} for {} items".format(time() - start, len(L)))
    #start = time()
    #merge_sort(L)
    #print("merge sort: {} for {} items".format(time() - start, len(L)))
    start = time()
    L3 = count_sort(L)
    print("count sort: {} for {} items".format(time() - start, len(L)))
    L2 = L[:] # let built-in sort in place...
    start = time()
    L2.sort()
    print("built-in sort: {} for {} items".format(time() - start, len(L)))
    print("count_sort in builtin sort equivalent: {}".format(L2 == L3))
