To sort Dart objects by an expensive computed value, calculate that value once per item, sort the resulting key–item pairs, then extract the items. This decorate-sort-undecorate pattern—also called the Schwartzian transform—can avoid repeating key work inside a comparator, but it is not automatically faster: it adds temporary storage and allocations.
How the Schwartzian transform works
A comparison sort may call its comparator many times. If the comparator parses, normalizes, or traverses data to derive a key each time, the same work can be repeated. The transform separates that work from sorting: decorate each item with its key, sort the decorated entries, then return the original items.
As an Amazon Associate I earn from qualifying purchases.
- Decorate: compute one key for each input item and store it alongside the item.
- Sort: compare the stored keys rather than recalculating them.
- Undecorate: extract the items in their new order.
Implement it for a Dart list
This version accepts a List<T>, computes each key once, and uses the original index to preserve input order when keys compare equal:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
List<T> sortedByKey<T, K extends Comparable<K>>(
List<T> items,
K Function(T) keyOf,
) {
final decorated = [
for (var i = 0; i < items.length; i++)
(key: keyOf(items[i]), index: i, value: items[i]),
];
decorated.sort((a, b) {
final byKey = a.key.compareTo(b.key);
return byKey != 0 ? byKey : a.index.compareTo(b.index);
});
return [for (final entry in decorated) entry.value];
}
For example, sortedByKey(records, (record) => record.normalizedName) sorts records using the computed name. The key type must support a meaningful compareTo order. See Dart’s Comparable documentation for intrinsic ordering; if a type has several useful orders, pass a comparator that expresses the order you need instead.
#1 Best Overall
The function takes a list because it uses indexed access and length. For a general Iterable<T>, materialize it first or enumerate it once to build the decorated entries. A compact alternative, when stable ties are unnecessary, is:
final decorated = items
.map((item) => (key: expensiveKey(item), item: item))
.toList();
decorated.sort((a, b) => a.key.compareTo(b.key));
final sortedItems = decorated.map((entry) => entry.item).toList();
Preserve the intended ordering
Dart’s comparator contract uses a negative result when the first value sorts before the second, zero when they compare equal, and a positive result when the first sorts after the second. The Dart List.sort documentation also warns: “The sort function is not guaranteed to be stable, so distinct objects that compare as equal may occur in any order in the result.”
Rank #2
The index in the first example is a secondary sort key: it makes equal-key items retain their input order without relying on sort stability. If that behavior does not matter, omit the index and its secondary comparison. For descending order, nullable keys, locale-aware strings, or composite keys, define the comparison deliberately; a simple compareTo may not express the ordering your data requires.
When precomputing keys may help
Precomputing is a candidate when deriving a key is costly and would otherwise be repeated during comparisons. It does not eliminate the sort itself: the program still computes one key per item, sorts the decorated entries, allocates temporary storage, and extracts the items afterward. If key extraction is cheap, a direct comparator is usually simpler.
Rank #3
Choose based on the key’s cost, input size and shape, memory pressure, and whether equal-key order must be preserved. There is no established Dart-specific benchmark or measured speedup that proves this technique is categorically faster. Treat the expected reduction in repeated key work as an algorithmic opportunity, not a performance guarantee.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.How to check whether it is faster in your application
Benchmark both approaches with representative data on the Dart SDK and runtime that matter to your application. Keep the key calculation, input sizes, and allocation conditions representative, and compare the same required ordering—including tie handling. Measure elapsed time and account for allocation and memory costs; do not infer a fixed percentage improvement from the technique alone. A recent discussion of the approach likewise reports no established Dart-specific result proving one method categorically faster: Dart sorting performance: Schwartzian transform vs. custom comparators.
Quick Recap
Rank #4
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →




