Sorting
Multi-Attribute Sorting
Data Structures
Algorithms
Programming Tips

Sort a list by multiple attributes?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Sorting by multiple attributes is a common requirement when records have several ranking rules. Typical examples are sorting people by department then salary, or products by category then price. Python makes this straightforward with tuple-based keys and stable sorting.

Sort with a Tuple Key

In Python, sorted and list.sort accept a key function. When that function returns a tuple, Python compares tuple elements from left to right.

python
1employees = [
2    {"name": "Ava", "team": "Platform", "level": 3, "salary": 110000},
3    {"name": "Noah", "team": "Platform", "level": 2, "salary": 98000},
4    {"name": "Mia", "team": "Data", "level": 2, "salary": 102000},
5    {"name": "Liam", "team": "Data", "level": 3, "salary": 125000},
6]
7
8ordered = sorted(employees, key=lambda e: (e["team"], e["level"], e["salary"]))
9for e in ordered:
10    print(e)

This sorts by team first, then level, then salary.

Mix Ascending and Descending Rules

One common need is ascending for some fields and descending for others. Numeric fields can be negated in the key for descending behavior.

python
1ordered = sorted(
2    employees,
3    key=lambda e: (e["team"], -e["level"], -e["salary"]),
4)

For text fields requiring descending order, perform multi-pass stable sorts.

python
1records = employees.copy()
2records.sort(key=lambda e: e["salary"], reverse=True)
3records.sort(key=lambda e: e["level"], reverse=True)
4records.sort(key=lambda e: e["team"])

Because Python sort is stable, earlier order for equal keys is preserved.

Sort Objects and Dataclasses

With objects, use attrgetter for cleaner key expressions.

python
1from dataclasses import dataclass
2from operator import attrgetter
3
4@dataclass
5class Order:
6    customer: str
7    priority: int
8    total: float
9
10orders = [
11    Order("A Corp", 2, 540.0),
12    Order("B Corp", 1, 900.0),
13    Order("A Corp", 1, 650.0),
14]
15
16result = sorted(orders, key=attrgetter("customer", "priority", "total"))
17print(result)

This style scales better than long lambda expressions when attributes grow.

Handle Missing Values Explicitly

Real data often has missing fields. Define a key that pushes missing values to the end.

python
1items = [
2    {"name": "p1", "score": 8},
3    {"name": "p2"},
4    {"name": "p3", "score": 5},
5]
6
7ordered = sorted(items, key=lambda x: (x.get("score") is None, x.get("score", 0)))
8print(ordered)

This avoids runtime errors and makes your rule intentional.

Locale and Case Handling for Text Fields

Text sorting can vary when case and locale matter. Normalize case in the key when you need predictable ordering.

python
cities = ["zurich", "Berlin", "amsterdam", "Tokyo"]
ordered = sorted(cities, key=lambda s: s.casefold())
print(ordered)

For locale-sensitive business output, use locale-aware transforms consistently across services and reports.

In-Place vs New List

Use sorted when you need a new list and want to preserve input order for other consumers. Use list.sort when mutating in place is acceptable and memory savings matter. Choosing explicitly helps prevent accidental side effects in shared data structures used across multiple functions.

Testing Multi-Attribute Sort Rules

Sorting bugs are easy to miss because output may still look mostly correct. Add focused tests that verify tie-breaking order.

python
1def sort_people(rows):
2    return sorted(rows, key=lambda r: (r["team"], -r["level"], r["name"]))
3
4sample = [
5    {"team": "A", "level": 2, "name": "Noah"},
6    {"team": "A", "level": 2, "name": "Ava"},
7]
8
9assert [p["name"] for p in sort_people(sample)] == ["Ava", "Noah"]

Tests like this protect ranking behavior from accidental changes.

Common Pitfalls

  • Mixing ascending and descending requirements without documenting key rules causes confusion.
  • Relying on implicit missing-value behavior can produce unstable or surprising ordering.
  • Using custom comparison functions instead of keys is slower and harder to maintain.
  • Sorting repeatedly in loops can become a major performance bottleneck.
  • Forgetting sort stability properties can lead to unnecessary complex code.

Summary

  • Use tuple keys for clear multi-attribute sorting.
  • Use numeric negation or stable multi-pass sorting for mixed order direction.
  • Prefer attrgetter for object and dataclass attributes.
  • Define missing-value behavior explicitly in sort keys.
  • Keep key functions cheap when sorting large lists.

Course illustration
Course illustration

All Rights Reserved.