A recent exercise in data processing with Ramda.js: I wanted to sort an array of objects by their key/value pairs. More specifically, I wanted to sort an array that looked like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
A basic implementation is easy enough:
1
|
|
R.sortBy
sorts according to a given function, in this case R.prop
(where 'silver'
could be substituted for any other property).
To ensure the order (ascending vs. descending), we can introduce R.comparator
:
1 2 |
|
How can we handle tiebreakers? That is, as in the example abolve, what if two elements in the array have identical gold
values and we attempt to sort by gold
— which should be sorted first? We can ensure a deterministic result with predictable tiebreaks using comparators and R.either
.
1 2 3 4 |
|
Finally, what if we need more than one tiebreaker? How do we handle objects that have identical gold
AND silver
values? R.either
expects two arguments, so the solution is to create a variadic implementation of R.either
, one that will accept an unknown number of arguments, so we can pass tiebreaker comparators for all possible situations:
1 2 3 4 5 6 7 8 |
|
The crux of this solution is variadicEither
, a variadic re-implementation of R.either
that can accept a variable number of arguments. It uses head
(first argument) and ...tail
(all remaining arguments) to reduce over all arguments and return a function that addresses all tiebreak possibilities. R.sort expects a comparator function, which R.either
and variadicEither
both return.
Of course this solution still has a bit of boilerplate (repetition of R.comparator(...)
). For a reusable sortByProps
implementation that takes an array of props and a list, see this Ramda.js recipe that I recently added.