File Coverage

blib/lib/Sort/Rank.pm
Criterion Covered Total %
statement 40 43 93.0
branch 12 18 66.6
condition 6 8 75.0
subroutine 7 7 100.0
pod 2 2 100.0
total 67 78 85.9


line stmt bran cond sub pod time code
1             package Sort::Rank;
2              
3 2     2   59373 use warnings;
  2         5  
  2         71  
4 2     2   11 use strict;
  2         3  
  2         68  
5 2     2   12 use Carp;
  2         7  
  2         378  
6              
7             require Exporter;
8             our @ISA = qw(Exporter);
9             our @EXPORT_OK = qw(rank_sort rank_group);
10              
11 2     2   1928 use version; our $VERSION = qv( '0.0.2' );
  2         5038  
  2         11  
12              
13             sub rank_group {
14 5     5 1 657813 my $array = shift;
15 5         14 my $extract = shift;
16              
17 5 50       31 if ( ref( $array ) eq 'HASH' ) {
18              
19             # Turn a hash into an array
20 0         0 my @a = map { [ $_, $array->{$_} ] } keys %$array;
  0         0  
21 0         0 $array = \@a;
22             }
23              
24 5 50       25 croak "rank_sort needs an array reference"
25             unless ref $array eq 'ARRAY';
26              
27             # Default score extraction sub
28             $extract ||= sub {
29 1007     1007   1020 my $item = shift;
30 1007 50 33     4153 croak "Array item must be a hash with a key called 'score'."
31             unless ref( $item ) eq 'HASH' && exists $item->{score};
32 1007         2777 return $item->{score};
33 5   100     31 };
34              
35 5 50       20 croak "Key extractor must be a code ref"
36             unless ref( $extract ) eq 'CODE';
37              
38 5         7 my $pos = 1;
39 34958 50       81547 my @ar = sort {
40              
41             # Sort on score then original position
42 4007         19058 $b->[0] <=> $a->[0]
43             || $a->[1] <=> $b->[1]
44             }
45             map {
46              
47             # Build array of score, original position, value
48 5         34 [ $extract->( $_ ), $pos++, $_ ]
49             } @$array;
50              
51 5         144 my @out = ();
52 5         26 for my $i ( 0 .. $#ar ) {
53              
54             # Need to start a new chunk?
55 4007 100 100     18428 if ( $i == 0 || $ar[$i]->[0] != $ar[ $i - 1 ]->[0] ) {
56 2204         5293 push @out, [ $i + 1 ];
57             }
58              
59             # Add item to current chunk
60 4007         8903 push @{ $out[-1] }, $ar[$i]->[2];
  4007         9963  
61             }
62              
63 5 100       1535 return wantarray ? @out : \@out;
64             }
65              
66             sub rank_sort {
67 1     1 1 49 my @grp = rank_group( @_ );
68 1         3 my @out = ();
69              
70             # Unwrap groups
71 1         3 for my $g ( @grp ) {
72 4         5 my $rank = shift @$g;
73 4 100       11 my $many = ( @$g > 1 ) ? '=' : '';
74 4         4 for my $i ( @$g ) {
75 7         23 push @out, [ $rank, $many, $i ];
76             }
77             }
78              
79 1 50       6 return wantarray ? @out : \@out;
80             }
81              
82             1;
83             __END__