sortLike<T, E> function
The sortLike function can be used to create a comparator to sort
collections, comparing a
and b
such that:
-
If
a
andb
are equal, the order betweena
andb
is undefined. -
Otherwise, If
a
andb
are not equal and both are present inorder
, then the order between them will be the same as inorder
. -
Otherwise, If both
a
andb
are not present inorder
, or only one of them is present and the other is not, andthen
is not provided, then the order betweena
andb
undefined. -
Otherwise, If both
a
andb
are not present inorder
, or only one of them is present and the other is not, andthen
is provided, then the order betweena
andb
with be given bythen
.
Optionally, you can provide a mapper
function, to convert a
and b
into the type of values in order
.
Notes
-
order
should be List or IList, otherwise it will be converted to a list in every use, which will hurt performance. -
If a value appears twice in
order
, only the first time counts.
This comparator makes it easy to create complex comparators, using the language described below. For example, suppose you have a list of numbers which you want to sort according to a certain order:
1) Order should be [7, 3, 4, 21, 2] when these values appear.
2) Otherwise, odd numbers come before even ones.
3) Otherwise, numbers come in their natural order.
int Function(int, int) compareTo = sortLike([7, 3, 4, 21, 2],
then: sortBy((x) => x % 2 == 1,
then: (int a, int b) => a.compareTo(b),
));
Important: When a cascade of sortLike is used, make sure you don't create
inconsistencies. For example, this is inconsistent: a < b
and a > c
and b < c
.
Sorts with inconsistent rules may result in different orders for the same
items depending on their initial position, and the rules may not be followed
precisely.
Implementation
int Function(T, T) sortLike<T, E>(
Iterable<E> order, {
E Function(T)? mapper,
int Function(T, T)? then,
}) =>
(T a, T b) {
if (a == b) return 0;
int posA, posB;
E ma, mb;
if (mapper != null) {
ma = mapper(a);
mb = mapper(b);
} else {
ma = a as E;
mb = b as E;
}
if (order is List<E>) {
posA = order.indexOf(ma);
posB = order.indexOf(mb);
} else if (order is IList<E>) {
posA = order.indexOf(ma);
posB = order.indexOf(mb);
} else {
final List<E> _order = order.toList();
posA = _order.indexOf(ma);
posB = _order.indexOf(mb);
}
return (posA != -1 && posB != -1)
? posA.compareTo(posB)
: (then == null)
? 0
: then(a, b);
};