List::OrderBy - Multi-key sorting using order_by and then_by
use List::OrderBy; my @sorted = order_by { ... } then_by { ... } then_by { ... } @unsorted;
Routines to generate ordered lists using key extraction code blocks with support for multi-key sorting.
The main routine takes a code block or subroutine reference and a list, applies the specified code to every element in the list to extract a sorting key, and then returns a list ordered according to the extracted keys, using sort and `<=>` internally. In the code block the list item value is available as $_, and subroutines are additionally called with the value as first parameter.
sort
$_
my @sorted = order_by { length } qw/xxx xx x/; # returns qw/x xx xxx/
In a chain starting with order_by, then_by specifies an additional ordering key extractor. The extracted key will be used to order elements if keys extracted by preceding order_by or then_by calls are equivalent.
order_by
then_by
my @sorted = order_by { $_->width } then_by { $_->height } @shapes;
This would first sort elements by their width and then by their height.
Same as order_by but uses descending order.
Same as order_by but uses cmp to compare extracted keys.
cmp
Analogous to the similarily named routines.
The functions order_by, then_by, order_cmp_by, then_cmp_by, order_by_desc, then_by_desc, order_cmp_by_desc, and then_cmp_by_desc, by default.
order_cmp_by
then_cmp_by
order_by_desc
then_by_desc
order_cmp_by_desc
then_cmp_by_desc
This module is mainly an experiment to see how Schwartzian transforms can be avoided in code, considering the pattern can be difficult to read, and it becomes unmaintainable with multiple keys. There are a number of issues though, like how to manage side-effects: should the module call a secondary key extractor even when the key is not actually needed? Should the module ensure that the key extractor is called only once? Does the ordering between calls to the key extractors matter?
Another problem is of course naming, order_by { ... } then_by { ... } is nice enough, but there does not seem to be a good way to add options like the comparison operator or ascending/descending behavior. Same for the side-effects question above if that was to be made configurable. A syntax with named parameters like in order_by :cmp :desc { ... } would be better but is not yet available with Perl5.
order_by { ... } then_by { ... }
order_by :cmp :desc { ... }
One gotcha I've noticed is with sorting strings by length. Since they are strings, you might be inclined to use a cmp variant, but order_cmp_by { length } usually is not what authors want. In a draft version of this module I actually called the routine order_strings_by, and switched to order_cmp_by to make it less misleading.
order_cmp_by { length }
order_strings_by
Copyright (c) 2013 Bjoern Hoehrmann <bjoern@hoehrmann.de>. This module is licensed under the same terms as Perl itself.
To install List::OrderBy, copy and paste the appropriate command in to your terminal.
cpanm
cpanm List::OrderBy
CPAN shell
perl -MCPAN -e shell install List::OrderBy
For more information on module installation, please visit the detailed CPAN module installation guide.