def bubbleSort_smarter(li):
    """Same as above, but we stop as soon as no changes are made (which means
    the list is sorted). We also don't need to go through the whole list on
    each iteration, as each iteration will push the highest element to the end,
    meaning we can ignore it in the next iteration.

    >>> bubbleSort_smarter([1, 2, 3, 4, 5])
    [1, 2, 3, 4, 5]
    >>> bubbleSort_smarter([5, 4, 3, 2, 1])
    [1, 2, 3, 4, 5]
    >>> bubbleSort_smarter([3, 2, 6, 1, 4, 2, 3, 1, 1, 5, 6, -2, 2.3])
    [-2, 1, 1, 1, 2, 2, 2.3, 3, 3, 4, 5, 6, 6]
    """

    n = len(li)
    step = 0
    changed = True
    while changed:
        changed = False
        for i in range(1, n-step):
            if li[i-1] > li[i]:
                li[i-1], li[i] = li[i], li[i-1]
                changed = True

    return li