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:

1
>>> 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:

1
2
3
>>> 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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
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 Number01234
List ElementsSurnameAddress2020-Census2016-Census2012-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:

1
2
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:

1
2
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:

1
2
3
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:

1
2
3
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:

1
2
3
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):

1
2
3
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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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.