2025, Nov 22 11:00

Sort a Python List of Lists by First Then Second Element (Lexicographic Ordering Explained)

Learn how to sort a Python list of lists by first and second elements using lexicographic order with tuple keys or slicing for predictable tie-breaking.

Sorting nested collections by multiple criteria is a routine task, yet it often trips people up when they try to preserve a primary order while layering a secondary one. The goal here is simple: order a list of lists by the first element, and if those match, by the second element. The data may contain strings in practice; numbers are used here only to keep the example compact.

Example that illustrates the problem

Suppose you start with the following structure and sort only by the first element. The result does not guarantee the intended order when the first elements are equal.

rows_src = [[3, 4, 3], [2, 6, 2], [2, 5, 6]]
primary_only = sorted(rows_src, key=lambda rec: rec[0])
print(primary_only)

This sorts by the first element but leaves ties unresolved by the second element, which is not what we want.

What’s really going on

The desired order is lexicographic: compare the first items, and if they are equal, compare the second items. This is exactly how Python already compares sequences like lists and tuples. That means you can either ask the sort key to produce something comparable in lexicographic order, or rely on the built-in sequence comparison directly. If you only want the first two positions to influence ordering, provide a key reflecting just those positions.

Solution: two equivalent ways

The first approach is to return a tuple with the first two elements from each inner list. Sorting by such a tuple enforces first-then-second priority without affecting the behavior beyond those positions.

data_rows = [[3, 4, 3], [2, 6, 2], [2, 5, 6]]
by_two_fields = sorted(data_rows, key=lambda rec: (rec[0], rec[1]))
print(by_two_fields)
# [[2, 5, 6], [2, 6, 2], [3, 4, 3]]

The second approach is to lean on the default lexicographic comparison of lists and simply call sorted without a key. This sorts by the first element, then the second, then the third, and so on. If your intent is strictly “first, then second” and you want to ignore any further positions, return only the first two by slicing in the key.

items = [[3, 4, 3], [2, 6, 2], [2, 5, 6]]
lex_default = sorted(items)
print(lex_default)

first_two_only = sorted(items, key=lambda rec: rec[:2])
print(first_two_only)
# [[2, 5, 6], [2, 6, 2], [3, 4, 3]]

These patterns apply equally when elements are strings. The ordering will follow the same rules, comparing the first string, then the second string if needed.

Why this matters

When sorting structured data, it is important to encode the intent precisely. Relying on a single-field key leaves ties unresolved in a way that may look arbitrary. Using lexicographic ordering—either implicitly by sorting the lists directly or explicitly by returning a two-element key—ensures predictable results. If only specific positions should influence the order, constrain the key to those positions to avoid unintended tie-breakers.

Takeaways

When you need “first, then second” ordering, either sort by a two-element key like lambda rec: (rec[0], rec[1]) or rely on the default list comparison with sorted(your_list). If you must ignore positions beyond the second, return only the first two elements with lambda rec: rec[:2]. This keeps the sort aligned with the problem statement and avoids breaking the first-level ordering while resolving ties consistently.