I have this code :
widget.items.sort((a, b) {
await getItemDistance(a, true);
await getItemDistance(b, false);
return (itemADistance)
.compareTo(itemBDistance);
});
I am trying to sort widget.items list based on values returned from getItemDistance. However I get an error with a red squiggly line that says :
The await expression can only be used in an async function
and when I try to add async to the sort method I get another red squiggly line that says :
The argument type 'Future Function(Item, Item)' can't be assigned to the parameter type 'int Function(Item, Item)'
How do I solve this dilemma guys ? :) Thanks
List.sort is a synchronous function that expects a synchronous callback; there is no way to use it with an asynchronous callback. I would recommend transforming your List and doing any necessary asynchronous work first and then synchronously sorting the results. Doing so also should avoid calling getItemDistance (which, by virtue of being asynchronous, is likely to be expensive) on the same item multiple times. For example, something like:
final computedDistances = <Item, double>{};
for (final item in widget.items) {
final distance = await getItemDistance(item, ...);
computedDistances[item] = distance;
}
widget.items.sort((a, b) =>
computedDistances[a].compareTo(computedDistances[b])
);
(I don't know what the second argument to getItemDistance represents; if you can't get around that, you would need to build one Map with getItemDistance(..., true) results and one with getItemDistance(..., false) results1.)
As a last resort, you could write your own asynchronous sort function.
This should be a more efficient version since it doesn't wait for each asynchronous operation one-by-one:
final computedDistances = await Future.wait<double>([
for (final item in widget.items) getItemDistance(item, ...),
]);
final computedDistancesMap = <Item, double>{
for (var i = 0; i < widget.items.length; i += 1)
widget.items[i]: computedDistances[i],
};
widget.items.sort((a, b) =>
computedDistancesMap[a].compareTo(computedDistancesMap[b])
);
I've added a List.sortWithAsyncKey extension method to package:dartbag that can do this :
await widget.items.sortWithAsyncKey(
(element) => getItemDistance(element, ...),
);
1 However, if you need to call getItemDistance(..., true) for the first argument and getItemDistance(..., false) for the second argument, that implies that your comparison function probably is not self-consistent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With