Python: Sort List From Second (or Nth Index) On

How do you sort a list by the second (or nth) element on in Python? How can you leave the first or nth elements in a list as they are but then have the remaining elements in the list sorted?

When applying the .sort() list method on a list Python will sort all elements in that list, but what if you only wanted to sort after a certain index number?

For example, suppose I had a list with the following contents:

>>> my_list = ['z', 'b', 'c', 'a']

And from this list, I wanted to keep the first element, 'z' , in the first position, but for the other elements in the list, I wanted them sorted. In other words, I wanted the list to produce the result of ['z', 'a', 'b', 'c'] .

Here’s how this can be achieved using a one-liner :

>>> my_list = ['z', 'a', 'b', 'c']
>>> my_list[:1] + sorted(my_list[1:])
['z', 'a', 'b', 'c']

It’s very important to use the built-in sorted() function rather than the .sort() list function as the .sort() list function will mutate the original list.

So where is this technique actually useful?

I have found working with dictionaries and outputting their result to CSV that this technique comes in very handy .

Here’s an example working with a list of dictionaries and outputting the result to CSV.

List Of Dictionaries To CSV With Ordered Headers

I had a recent need while programming in Python where I needed to sort after the second element onwards . I was outputting a CSV file from a List[Dict] and I wanted the output of the resulting csv file to mimic the order of the first few Dict values, but then after the second element in the list I wanted to rearrange the order of the list by sorting it.

Here is a simplified representation of the Dict and the resulting List :

data = [{
'Surname': "Smith",
'Address': "1 Way Road, TEST",
'2020-Census': 4,
'2016-Census': 3,
'2012-Census': 2
},
{...}]

# get list of keys for csv.DictWriter
keys_list = list(data[0].keys())

# display list
print(keys_list)
# ['Surname', 'Address', '2020-Census', '2016-Census', '2012-Census']

The output desired of the csv file was to keep the Surname and Address columns at the front of the resulting csv file, but then for the remaining 20XX-Census fields to be placed in a specific order.

To order the keys list the way I need, I would have to slice the list to remove the fields I want static, then with other fields I would sort them and then concatenate them together.

Step 1 – Get Sorting List

In my example here, the first two elements in the list I need to remain static, but the rest I need to sort. The easiest way to perform this operation is to slice the list using the slice operator.

If you recall a List is made up of elements that have an index, and could be shown using a diagram like so:

Index Number 0 1 2 3 4
List Elements Surname Address 2020-Census 2016-Census 2012-Census
The index numbers of a List in Python

Therefore, to obtain a section of the list for sorting using the slice operator, I need everything after the second element .

To use the slice operator, we need to recall that it’s syntax looks as follows:

List|String[{start}:{stop{:step}}]

The syntax for using the slice operator on a List or String is that you can enter a starting index number in the start area, (it is optional, and this is why it is wrapped with {} ) and this starting index number is inclusive. Therefore, if we were to slice our List above after the second element, we would enter the slice operator as follows:

keys_list[2:]
# ['2020-Census', '2016-Census', '2012-Census']

As we wanted this list to continue to the end, we didn’t apply any value in the stop section of the slice operator. We could have placed the value of 6 in the stop value for the slice operator, and this would achieved the same result:

keys_list[2:6]
# ['2020-Census', '2016-Census', '2012-Census']

As I prefer the former example, where no stop value was placed, and I want to capture this as a separate list, I then used the following operation:

order_list = keys_list[2:]
print(order_list)
# ['2020-Census', '2016-Census', '2012-Census']

Now that I have the list of entries that I want to sort, I can apply a sort on this list.

Step 2 – Sort List

With our sorting list available, we can apply one of two ways to sort: we can mutate the list, or not mutate the list. By mutating the list, the order of the list will be changed permanently. Let’s do that and show the result:

order_list.sort()
print(order_list)
# ['2012-Census', '2016-Census', '2020-Census']

By applying the .sort() list method on our order_list variable, the order of the list has now permanently changed.

Step 3 – Concatenate List

Finally, to put this list back together to form the fieldnames parameter needed for the csv.DictWriter function, we simply apply the + operator to both lists:

new_keys_list = keys_list[:2] + order_list
print(new_keys_list)
# ['Surname', 'Address', '2012-Census', '2016-Census', '2020-Census']

One Liner

Or, if you wanted to perform a sort after the second element you could do it as a one-liner (using the sorted function which does not mutate the original list):

sorted_list = keys_list[:2] + sorted(keys_list[2:])
print(sorted_list)
# ['Surname', 'Address', '2012-Census', '2016-Census', '2020-Census']

Or, to turn it into something useable if you find this becomes a common function in your code, but instead of it being the second element it was something different like the nth element , we could write a function as follows:

from typing import List


def sorted_list_from_nth_element(l: List, n: int, reverse: bool = False) -> List:
    """
    :param l: list to obtain elements from
    :param n: nth element to keep static, same as index number of first element to sort from
    :param reverse: default is ascending order, if descending order needed set to True
    """
    return l[:n] + sorted(l[n:], reverse=reverse)


# noticed I've jumbled the order here to demonstrate, ascending & descending
key_list = ['Surname', 'Address', '2016-Census', '2020-Census', '2012-Census']

# ascending list
asc_list = sorted_list_from_nth_element(key_list, 2)
print(asc_list)
# ['Surname', 'Address', '2012-Census', '2016-Census', '2020-Census']

# descending list
desc_list = sorted_list_from_nth_element(key_list, 2, True)
print(desc_list)
# ['Surname', 'Address', '2020-Census', '2016-Census', '2012-Census']

# ...and to show the original list hasn't mutated
print(key_list)
# ['Surname', 'Address', '2016-Census', '2020-Census', '2012-Census']

Summary

In this article I discovered how to sort a list in python after the second element onwards which was a requirement I had in a current Python project. I also showed the differences between using the .sort() method on a list which mutates the original list, and a non-mutating function sorted() that returns a new list and doesn’t mutate the original list.

Once we had sorted the portion of the original list it was then a simple matter of concatenating the non-sorted portion with the sorted portion using the + operator.

Photo of author
Ryan Sheehy
Ryan has been dabbling in code since the late '90s when he cut his teeth exploring VBA in Excel. Having his eyes opened with the potential of automating repetitive tasks, he expanded to Python and then moved over to scripting languages such as HTML, CSS, Javascript and PHP.