Sort a list from an index to another index - python

TL;DR:

Use sorted with a slicing assignment to keep the original list object without creating a new one:

l = [2, 4, 1, 3, 5]
l[1:] = sorted(l[1:])
print(l)

Output:

[2, 1, 3, 4, 5]

Longer Answer:

After the list is created, we will make a slicing assignment:

l[1:] = 

Now you might be wondering what does [1:], it is slicing the list and starts from the second index, so the first index will be dropped. Python's indexing starts from zero, : means get everything after the index before, but if it was [1:3] it will only get values that are in between the indexes 1 and 3, let's say your list is:

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

If you use:

print(l[1:])

It will result in:

[2, 3, 4, 5]

And if you use:

print(l[1:3])

It will result in:

[2, 3]

About slicing, read more here if you want to.

And after slicing we have an equal sign =, that just simply changes what's before the = sign to what's after the = sign, so in this case, we use l[1:], and that gives [2, 3, 4, 5], it will change that to whatever is after the = sign.

If you use:

l[1:] = [100, 200, 300, 400]
print(l)

It will result in:

[1, 100, 200, 300, 400]

To learn more about it check out this.

After that, we got sorted, which is default builtin function, it simple sorts the list from small to big, let's say we have the below list:

l = [3, 2, 1, 4]

If you use:

print(sorted(l))

It will result in:

[1, 2, 3, 4]

To learn more about it check this.

After that we come back to our first topic about slicing, with l[1:], but from here you know that it isn't only used for assignments, you can apply functions to it and deal with it, like here we use sorted.


Maybe temporarily put something there that's smaller than the rest? Should be faster than the other solutions. And gets as close to your "No extra spaces" wish as you can get when using sort or sorted.

>>> tmp = l[0]
>>> l[0] = float('-inf')
>>> l.sort()
>>> l[0] = tmp
>>> l
[2, 1, 3, 4, 5]


Benchmarks

For the example list, 1,000,000 iterations (and mine of course preparing that special value only once):

  sort_u10 0.8149 seconds
sort_chris 0.8569 seconds
 sort_heap 0.7550 seconds
sort_heap2 0.5982 seconds   # using -1 instead of -inf

For 50,000 lists like [int(x) for x in os.urandom(100)]:

  sort_u10 0.4778 seconds
sort_chris 0.4786 seconds
 sort_heap 0.8106 seconds
sort_heap2 0.4437 seconds   # using -1 instead of -inf

Benchmark code:

import timeit, os

def sort_u10(l):
    l[1:] = sorted(l[1:])

def sort_chris(l):
    l = l[:1] + sorted(l[1:])

def sort_heap(l, smallest=float('-inf')):
    tmp = l[0]
    l[0] = smallest
    l.sort()
    l[0] = tmp

def sort_heap2(l):
    tmp = l[0]
    l[0] = -1
    l.sort()
    l[0] = tmp

for _ in range(3):
    for sort in sort_u10, sort_chris, sort_heap, sort_heap2, sort_rev:
        number, repeat = 1_000_000, 5
        data = iter([[2, 4, 1, 3, 5] for _ in range(number * repeat)])
        # number, repeat = 50_000, 5
        # data = iter([[int(x) for x in os.urandom(100)] for _ in range(number * repeat)])
        t = timeit.repeat(lambda: sort(next(data)), number=number, repeat=repeat)
        print('%10s %.4f seconds' % (sort.__name__, min(t)))
    print()

Use sorted with slicing:

l[:1] + sorted(l[1:])

Output:

[2, 1, 3, 4, 5]

Tags:

Python

Sorting