Compare records with a locale-independent comparison key

Compare records with a locale-independent comparison key

By Batu

Sorting display text directly can make ordering depend on the process locale when a program uses locale-aware comparison functions. A comparison key can make the chosen rule explicit instead. This recipe uses str.casefold() to create an aggressive Unicode case-insensitive key, then returns (name.casefold(), record_id). The integer record_id supplies a deterministic tie-breaker when names fold to the same value.

The records ("Beta", 2), ("alpha", 3), and ("ALPHA", 1) sort to IDs 1, 3, then 2. Both spellings of alpha share the first key component "alpha", so the second component orders IDs one and three. Python compares tuples lexicographically, and sorted() evaluates the key once per input item before sorting, which keeps the key function straightforward.

This is locale-independent because the code neither reads nor changes LC_COLLATE, and casefold() follows Unicode case-folding rules rather than the host's collation tables. It is not a culturally correct collation algorithm: accented characters, language-specific ordering, normalization-equivalent spellings, and user expectations may require an ICU-style collation service. casefold() is also for comparison, not for preserving display text; the original names remain in the records and are printed unchanged.

AI assistance was used to draft this article.

records = [
    ("Beta", 2),
    ("alpha", 3),
    ("ALPHA", 1),
]


def comparison_key(record: tuple[str, int]) -> tuple[str, int]:
    name, record_id = record
    return (name.casefold(), record_id)


ordered = sorted(records, key=comparison_key)
ordered_ids = [record_id for _, record_id in ordered]

assert ordered_ids == [1, 3, 2]
assert [comparison_key(record) for record in ordered][:2] == [
    ("alpha", 1),
    ("alpha", 3),
]
for name, record_id in ordered:
    print(f"{record_id}:{name}")

Expected stdout:

1:ALPHA
3:alpha
2:Beta

Sources

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic