Lodash orderBy Sort Stability Explained
Lodash's _.orderBy provides a guaranteed stable sort
when processing collections in JavaScript. When multiple elements
produce identical values across all specified sorting criteria, Lodash
preserves their original relative order from the input array. This
article explains how _.orderBy handles complete ties, the
mechanism behind its stability guarantee, and how it impacts predictable
data sorting.
The Stability Guarantee
A sorting algorithm is considered stable if it preserves the original
relative order of elements with equal sorting keys. When using Lodash's
_.orderBy(collection, [iteratees=[_.identity]], [orders]),
the function evaluates elements sequentially across the provided
iteratees.
If two or more items have identical values for the first sorting
criteria, the algorithm moves to the second criteria, and so forth. If
two elements tie across every specified iteratee and
corresponding sort order, _.orderBy guarantees stability by
retaining the sequence in which those elements initially appeared in the
source array.
How Lodash Resolves Ties
Internally, Lodash maps the original collection into intermediate objects that pair each element with its computed sorting criteria and its original index in the source array. This technique is often referred to as a Schwartzian transform.
During the comparison phase:
- Lodash evaluates the criteria from left to right according to the
directions specified in
orders('asc'or'desc'). - If all user-defined criteria produce an exact match (a tie), Lodash uses the element's original index as the final tiebreaker.
- The original index is always evaluated in ascending order, ensuring that whichever tied item appeared first in the input collection appears first in the final output.
Practical Example of an Exact Tie
Consider the following collection sorted by role and
age:
const users = [
{ id: 1, name: 'Alice', role: 'admin', age: 30 },
{ id: 2, name: 'Bob', role: 'user', age: 25 },
{ id: 3, name: 'Charlie', role: 'admin', age: 30 },
{ id: 4, name: 'Diana', role: 'user', age: 25 }
];
const result = _.orderBy(users, ['role', 'age'], ['asc', 'desc']);In this scenario:
- Both
AliceandCharliehaverole: 'admin'andage: 30. - Both
BobandDianahaverole: 'user'andage: 25.
Because all specified sorting criteria evaluate to the same values
for these pairs, the exact tie fallback activates. Alice
(index 0) is guaranteed to precede Charlie (index 2), and
Bob (index 1) is guaranteed to precede Diana
(index 3) in the resulting array.
Independent of Runtime Quirks
While ECMAScript 2019 (ES10) mandated that the native
Array.prototype.sort must be stable, earlier JavaScript
engine implementations did not guarantee stability for large arrays.
Lodash’s internal index-tracking mechanism ensures that
_.orderBy remains deterministic and stable across all
JavaScript runtimes, environments, and array sizes without relying on
native sorting quirks.