To sort Dart objects by an expensive computed value without recalculating that value during comparisons, compute the key once per item, store it beside the item, sort the stored pairs, then extract the items. The essential detail is to call .toList() on the decorated values: Iterable.map is lazy and does not cache conversions.
What is the Schwartzian transform?
Also called decorate-sort-undecorate, the Schwartzian transform has three stages: attach a derived sort key to each item, sort those decorated items by the saved key, then remove the decoration. It is useful when calculating a key inside a comparator would repeat costly work. The approach uses extra storage, so it is a trade-off rather than a guaranteed speedup.
As an Amazon Associate I earn from qualifying purchases.
How to sort by a computed property in Dart
This example uses Dart records to keep each item paired with its key:
final decorated = items
.map((item) => (item: item, key: expensiveKey(item)))
.toList();
decorated.sort((a, b) => a.key.compareTo(b.key));
final sortedItems = decorated.map((entry) => entry.item).toList();
- Decorate: calculate the key once for each input item and store the item and key together.
- Materialize: call
.toList()so the decorations are stored rather than lazily recalculated. - Sort: compare the saved keys in the comparator.
- Undecorate: extract the original items into the result list.
This record syntax requires a Dart version that supports records. For older language versions, use a small typed helper class with item and key fields. Check the project’s SDK constraint; the available documentation does not establish a minimum SDK version here.
#1 Best Overall
Why materializing map() matters
Dart’s Iterable.map is lazy: it applies the conversion as you iterate, and it does not cache converted values between iterations. If you keep a mapped iterable as though it were saved key storage, iterating it again can run the key calculation again. Calling .toList() on the decorated iterable creates the concrete list needed for this technique.
Keep duplicate keys paired with their items
Make one decoration for every input item, even when several items have the same key. Sorting those pairs keeps each item attached to its own key. Do not use a map from key to item as a substitute when keys may repeat: Map.fromIterable permits duplicate generated keys, and later values overwrite earlier ones.
Rank #2
Make tie ordering explicit when it matters
The reviewed Dart List.sort documentation does not promise a stable sort, so equal keys should not be assumed to retain their input order. Store each item’s original index and use it as a secondary comparison when the primary keys compare equal:
final decorated = items
.asMap()
.entries
.map((entry) => (
item: entry.value,
key: expensiveKey(entry.value),
index: entry.key,
))
.toList();
decorated.sort((a, b) {
final byKey = a.key.compareTo(b.key);
return byKey != 0 ? byKey : a.index.compareTo(b.index);
});
final sortedItems = decorated.map((entry) => entry.item).toList();
The index makes the desired tie order part of the comparator rather than relying on a sort stability guarantee. Dart comparator callbacks should return a negative number when the first value comes earlier, zero when the values are equivalent, and a positive number when the first comes later.
Rank #3
What sorting changes about the source list
List.sort sorts the list on which it is called. The examples sort a separate decorated list, leaving the original list’s order intact, and create a separate output list. Dart’s List API also says changing a list’s length during operations such as sorting is generally disallowed.
Plan the key and comparator for your data
Decide the ordering rules before implementing the comparator. For example, specify whether null sorts first or last, whether strings need case folding or locale-aware collation, and how equal primary keys should be ordered. Precompute expensive normalization in the decoration, and test representative edge cases. The comparator must be consistent; these ordering choices are application-specific, not defaults established by the APIs cited here.
Rank #4
When is the transform worthwhile?
Compare the cost of repeated key calculation with the extra allocation and storage of decorated values. The benefit depends on the data, key function, sort behavior, and runtime. No Dart-specific benchmark or performance crossover figure is established here, so benchmark representative data before claiming a speed gain.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteQuick Recap
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.




