Ordering — Composable Comparators
Sorting a collection is straightforward when we only care about a single, simple field:
However, as soon as we need to sort across multiple criteria — say, grouping employees by department, and then sorting by salary within each department — our code quickly becomes cluttered with manual tiebreaker logic:
This code is verbose, tedious to write, and prone to copy-paste bugs. Crucially, these comparators
do not compose. You cannot take an existing byDepartment checker and a bySalary checker and
combine them into a third comparator without rewriting the nested logic from scratch.
Ordering<A> solves this problem. It represents a first-class, pure comparator:
A positive return number means the first element comes after the second; a negative number means it
comes before; and zero indicates a tie. Because Ordering matches the standard JavaScript
comparator signature, it is 100% compatible with native runtime APIs.
Built-In Ordering Instances
Section titled “Built-In Ordering Instances”The library provides optimized, built-in ordering instances for primitive types:
Reversing Sort Order: reverse
Section titled “Reversing Sort Order: reverse”Ordering.reverse flips the sorting direction of any existing comparator:
Adapting Keys: by
Section titled “Adapting Keys: by”Ordering.by adapts an ordering checker designed for a simpler type A so that it operates on a
richer type B by extracting the field to compare:
Combining Comparators: thenBy
Section titled “Combining Comparators: thenBy”Ordering.thenBy allows you to chain two ordering checkers together, using the second checker as a
tiebreaker only when the first check evaluates to a tie (0):
Multi-Column Sorting: byFields
Section titled “Multi-Column Sorting: byFields”When you need to aggregate an arbitrary list of field comparators — such as multi-column data tables
where users can sort by dynamic combinations of columns — Ordering.byFields combines an array of
Ordering<A> instances into a single composite comparator:
It evaluates each comparator sequentially until it finds a non-zero comparison result, short-circuiting early once a tie is broken.
Practical Application: Immutable Sorting
Section titled “Practical Application: Immutable Sorting”Arr.sortWith accepts any Ordering<A> instance and returns a fresh, sorted array, avoiding
the mutability issues associated with JavaScript’s native Array.prototype.sort:
Problems it solves
Section titled “Problems it solves”- Multi-column table sorting with tiebreakers: In data grids and table views, users frequently
sort records by multiple criteria (such as status first, then created date descending, then name
ascending). Writing chained ternary comparator callbacks manually is error-prone.
Ordering.byandOrdering.thencombine atomic sorting rules into readable tiebreaker pipelines. - Preventing in-place array mutation: Native
Array.prototype.sort()mutates the source array in place, causing race conditions and UI state bugs in reactive stores. PairingOrderingcomparators withArr.sortWithproduces a new sorted array while preserving the original dataset immutably. - Custom priority hierarchies and status rankings: Sorting domain entities by non-alphabetical
business rules (such as
urgent>high>medium>low) with composable custom comparators. - Reusable and reversible comparator definitions: Instead of redefining inline sorting callbacks
across different endpoints and components,
Orderingallows domain comparators (such as chronological order or priority rankings) to be named, shared, and reversed viaOrdering.reverse.