sortLike<T, E> function

int Function(T, T) sortLike<T, E>(
  1. Iterable<E> order, {
  2. E mapper(
    1. T
    )?,
  3. int then(
    1. T,
    2. T
    )?,
})

The sortLike function can be used to create a comparator to sort collections, comparing a and b such that:

  • If a and b are equal, the order between a and b is undefined.

  • Otherwise, If a and b are not equal and both are present in order, then the order between them will be the same as in order.

  • Otherwise, If both a and b are not present in order, or only one of them is present and the other is not, and then is not provided, then the order between a and b undefined.

  • Otherwise, If both a and b are not present in order, or only one of them is present and the other is not, and then is provided, then the order between a and b with be given by then.

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.

Note sortLike can be combined with sortBy.

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 {
        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);
    };