""" Merge sort """


def merge_sort(lst):
    """ Return a sorted list with the same elements as lst

    This is a non-mutating version of merge sort.

    @param list lst: list of comparable objects
    @rtype: list of comparable objects

    >>> from random import shuffle
    >>> 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(lst) < 2:
        return lst[:]
    else:
        mid = len(lst) // 2  # divide
        # recursively solve subproblems
        left_sorted = merge_sort(lst[:mid])
        right_sorted = merge_sort(lst[mid:])
        # combine
        return merge(left_sorted, right_sorted)


def merge(lst1, lst2):
    """ Return a sorted list with the elements of lst1 and lst2

    >>> 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]
    """
    lst = []
    i1 = 0  # index of next thing to merge in lst1
    i2 = 0  # index of next thing to merge in lst2
    while i1 < len(lst1) and i2 < len(lst2):
        if lst1[i1] < lst2[i2]:
            lst.append(lst1[i1])
            i1 += 1
        else:
            lst.append(lst2[i2])
            i2 += 1
    return lst + lst1[i1:] + lst2[i2:]


if __name__ == '__main__':
    import doctest
    doctest.testmod()
