Skip to main content

How to Sort a List of Tuples by Second or Multiple Elements in Python

Lists containing tuples are a common way to structure related data in Python. Often, you need to sort this list based on the value of a specific element within each tuple (like the second element) or based on multiple elements acting as primary and secondary sort keys. Python's sorted() function and list.sort() method provide powerful ways to achieve this using the key argument.

This guide demonstrates how to sort lists of tuples by the second element or multiple elements, in both ascending and descending order.

Sorting Fundamentals: The key Argument

Both the built-in sorted() function (which returns a new sorted list) and the list.sort() method (which sorts the list in-place) accept an optional key argument.

  • key: This argument takes a function. This function is called on each element of the list before comparisons are made. The return value of this key function is then used as the basis for the sorting comparison.

This allows you to sort based on criteria other than the default element-by-element comparison of the tuples.

Sort by the Second Element (Index 1)

To sort based solely on the value at index 1 (the second element) of each tuple.

Using sorted() with lambda (Ascending)

Provide a lambda function to the key argument that extracts the element at index 1 from each tuple.

data = [('Apple', 50), ('Banana', 20), ('Cherry', 30), ('Date', 20)]

# Sort based on the number (index 1) in ascending order
sorted_data = sorted(data, key=lambda tup: tup[1])

print(f"Original: {data}")
# Output: Original: [('Apple', 50), ('Banana', 20), ('Cherry', 30), ('Date', 20)]

print(f"Sorted by 2nd element (Asc): {sorted_data}")
# Output: Sorted by 2nd element (Asc): [('Banana', 20), ('Date', 20), ('Cherry', 30), ('Apple', 50)]

Output:

Original: [('Apple', 50), ('Banana', 20), ('Cherry', 30), ('Date', 20)]
Sorted by 2nd element (Asc): [('Banana', 20), ('Date', 20), ('Cherry', 30), ('Apple', 50)]
  • lambda tup: tup[1]: This anonymous function takes a tuple tup and returns its second element (tup[1]). sorted() uses these returned values (20, 20, 30, 50) for comparison.
note

Python's sort is stable. When keys are equal (like the two 20s), the original relative order of the elements ('Banana' then 'Date') is preserved.

Using sorted() with lambda (Descending)

To sort in descending order (largest to smallest based on the key), add the reverse=True argument.

data = [('Apple', 50), ('Banana', 20), ('Cherry', 30), ('Date', 20)]

# Sort based on the number (index 1) in descending order
sorted_data_desc = sorted(data, key=lambda tup: tup[1], reverse=True)

print(f"Original: {data}")
# Output: Original: [('Apple', 50), ('Banana', 20), ('Cherry', 30), ('Date', 20)]

print(f"Sorted by 2nd element (Desc): {sorted_data_desc}")
# Output: Sorted by 2nd element (Desc): [('Apple', 50), ('Cherry', 30), ('Banana', 20), ('Date', 20)]

Output:

Original: [('Apple', 50), ('Banana', 20), ('Cherry', 30), ('Date', 20)]
Sorted by 2nd element (Desc): [('Apple', 50), ('Cherry', 30), ('Banana', 20), ('Date', 20)]

Using sorted() with operator.itemgetter

The operator.itemgetter function provides a slightly more efficient way to create the key function for accessing elements by index.

from operator import itemgetter # Required import

data = [('Apple', 50), ('Banana', 20), ('Cherry', 30), ('Date', 20)]

# Sort based on index 1 using itemgetter (Ascending)
sorted_data_itemgetter = sorted(data, key=itemgetter(1))
print(f"Sorted by 2nd element (itemgetter Asc): {sorted_data_itemgetter}")
# Output: Sorted by 2nd element (itemgetter Asc): [('Banana', 20), ('Date', 20), ('Cherry', 30), ('Apple', 50)]

# Descending with itemgetter
sorted_data_itemgetter_desc = sorted(data, key=itemgetter(1), reverse=True)
print(f"Sorted by 2nd element (itemgetter Desc): {sorted_data_itemgetter_desc}")
# Output: Sorted by 2nd element (itemgetter Desc): [('Apple', 50), ('Cherry', 30), ('Banana', 20), ('Date', 20)]

Output:

Sorted by 2nd element (itemgetter Asc): [('Banana', 20), ('Date', 20), ('Cherry', 30), ('Apple', 50)]
Sorted by 2nd element (itemgetter Desc): [('Apple', 50), ('Cherry', 30), ('Banana', 20), ('Date', 20)]
  • key=itemgetter(1): Creates a callable that directly fetches the element at index 1. Often preferred for simple index-based keys over lambda.

Sort by Multiple Elements (Primary, Secondary Keys, etc.)

To sort based on multiple criteria (e.g., sort by the second element, and for ties, sort by the third element), have the key function return a tuple of the values you want to sort by, in the desired order of priority. Python compares tuples element by element.

Using sorted() with lambda Returning a Tuple (Ascending)

The lambda function should return a tuple like (primary_key_element, secondary_key_element, ...).

# List of (ID, Category, Value)
data = [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75), (4, 'C', 50), (5, 'B', 60)]

# Sort primarily by Category (index 1), then secondarily by Value (index 2) - Ascending for both
sorted_multi = sorted(data, key=lambda tup: (tup[1], tup[2]))

print(f"Original: {data}")
# Output: Original: [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75), (4, 'C', 50), (5, 'B', 60)]
print(f"Sorted by Cat (1), then Val (2): {sorted_multi}")
# Output: Sorted by Cat (1), then Val (2): [(3, 'A', 75), (1, 'A', 100), (2, 'B', 50), (5, 'B', 60), (4, 'C', 50)]

Output:

Original: [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75), (4, 'C', 50), (5, 'B', 60)]
Sorted by Cat (1), then Val (2): [(3, 'A', 75), (1, 'A', 100), (2, 'B', 50), (5, 'B', 60), (4, 'C', 50)]
  • key=lambda tup: (tup[1], tup[2]): Returns tuples like ('A', 75), ('A', 100), ('B', 50), etc.
  • Python compares these tuples: ('A', 75) comes before ('A', 100) because 75 < 100. ('A', ...) comes before ('B', ...) because 'A' < 'B'.

Using sorted() with lambda Returning a Tuple (Descending)

Use reverse=True to reverse the overall sort order based on the tuple comparison.

data = [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75), (4, 'C', 50), (5, 'B', 60)]

# Sort primarily by Category (index 1), then secondarily by Value (index 2) - Descending overall
sorted_multi_desc = sorted(data, key=lambda tup: (tup[1], tup[2]), reverse=True)

print(f"Original: {data}")
# Output: Original: [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75), (4, 'C', 50), (5, 'B', 60)]
print(f"Sorted by Cat (1), then Val (2) DESC: {sorted_multi_desc}")
# Output: Sorted by Cat (1), then Val (2) DESC: [(4, 'C', 50), (5, 'B', 60), (2, 'B', 50), (1, 'A', 100), (3, 'A', 75)]

Output:

Original: [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75), (4, 'C', 50), (5, 'B', 60)]
Sorted by Cat (1), then Val (2) DESC: [(4, 'C', 50), (5, 'B', 60), (2, 'B', 50), (1, 'A', 100), (3, 'A', 75)]
note

If you need mixed ascending/descending order (e.g., Category ascending, Value descending), you often need multiple sort passes or more complex key functions (like multiplying numeric secondary keys by -1 for reverse numeric sort).

Using sorted() with operator.itemgetter

itemgetter can also fetch multiple indices, returning them as a tuple, making it suitable for multi-key sorting.

from operator import itemgetter # Required import

data = [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75), (4, 'C', 50), (5, 'B', 60)]

# Sort by index 1, then index 2 using itemgetter (Ascending)
sorted_multi_itemgetter = sorted(data, key=itemgetter(1, 2))
print(f"Sorted by Cat (1), then Val (2) (itemgetter): {sorted_multi_itemgetter}")
# Output: Sorted by Cat (1), then Val (2) (itemgetter): [(3, 'A', 75), (1, 'A', 100), (2, 'B', 50), (5, 'B', 60), (4, 'C', 50)]

# Descending overall
sorted_multi_itemgetter_desc = sorted(data, key=itemgetter(1, 2), reverse=True)
print(f"Sorted by Cat (1), then Val (2) (itemgetter Desc): {sorted_multi_itemgetter_desc}")
# Output: Sorted by Cat (1), then Val (2) (itemgetter Desc): [(4, 'C', 50), (5, 'B', 60), (2, 'B', 50), (1, 'A', 100), (3, 'A', 75)]

Output:

Sorted by Cat (1), then Val (2) (itemgetter): [(3, 'A', 75), (1, 'A', 100), (2, 'B', 50), (5, 'B', 60), (4, 'C', 50)]
Sorted by Cat (1), then Val (2) (itemgetter Desc): [(4, 'C', 50), (5, 'B', 60), (2, 'B', 50), (1, 'A', 100), (3, 'A', 75)]
  • key=itemgetter(1, 2): Creates a callable that fetches elements at index 1 and 2, returning them as a tuple (element_at_1, element_at_2).

In-Place Sorting using list.sort()

If you want to modify the original list directly instead of creating a new sorted list, use the list.sort() method. It accepts the same key and reverse arguments.

from operator import itemgetter

data_to_sort = [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75)]
print(f"Original list (before sort): {data_to_sort}")
# Output: Original list (before sort): [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75)]

# Sort the list in-place by index 1, then 2
data_to_sort.sort(key=itemgetter(1, 2)) # No return value needed, list is modified

print(f"Original list (after sort): {data_to_sort}")
# Output: Original list (after sort): [(3, 'A', 75), (1, 'A', 100), (2, 'B', 50)]

Output:

Original list (before sort): [(1, 'A', 100), (2, 'B', 50), (3, 'A', 75)]
Original list (after sort): [(3, 'A', 75), (1, 'A', 100), (2, 'B', 50)]
  • list.sort() modifies the list directly and returns None.

Choosing Between sorted() and list.sort()

  • Use sorted(my_list, ...) when you want to keep the original list unchanged and get a new sorted list.
  • Use my_list.sort(...) when you want to modify the original list in-place and don't need to preserve the original order (this can be slightly more memory efficient as it doesn't create a new list).

Conclusion

Python's sorting functions are highly flexible for lists of tuples thanks to the key argument:

  • To sort by the second element (index 1), use key=lambda t: t[1] or key=operator.itemgetter(1).
  • To sort by multiple elements (e.g., index 1 then index 2), use key=lambda t: (t[1], t[2]) or key=operator.itemgetter(1, 2). The key function should return a tuple representing the sort priority.
  • Use reverse=True with either sorted() or list.sort() for descending order based on the key.
  • Choose sorted() to get a new list or list.sort() to modify the list in-place.

Leveraging the key argument provides precise control over how lists of tuples are ordered based on their internal elements.