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.