in reply to Re^5: Building a sorting subroutine on the fly
in thread Building a sorting subroutine on the fly

Thank you very much, Tanktalus. This is helpful and thought-provoking. A number of points:

  1. The 'a' option is for alphabetical search -- which implies using lc() around each side of the comparison. The 's' option is for ASCII-betical (case-insensitive) search.

  2. I've rarely used the do {} construction:

    my %cols_idx = do { my $i = 0; map { $_ => $i++ } @cols };

    I'll have to start paying more attention to that.

  3. Your use of map is one of the most terse usages I've ever seen:

    my @data = map [ split " " ] => <DATA>;

    I'm not even sure I understand how the square brackets work instead of parentheses.

Imposing my own coding practices on what you wrote, I've come up with this:

#!/usr/local/bin/perl use strict; use warnings; use Data::Dumper; my @cols = qw ( lastname firstname cno unit ward dateadmission datebirth ); my %cols_idx = do { my $i = 0; map { $_ => $i++ } @cols }; my %parameters = ( lastname => [ qw( U a ) ], firstname => [ qw( U a ) ], cno => [ qw( U n ) ], unit => [ qw( U s ) ], ward => [ qw( U n ) ], dateadmission => [ qw( D a ) ], datebirth => [ qw( D a ) ], ); my @data = map [ split ] => <DATA>; print Dumper sort_by_column( \@data, @ARGV ? @ARGV : qw{ lastname firstname cno } ); ########## SUBROUTINES ########## sub make_single_comparator { print "parms: @_\n"; my $data = shift; my $col = shift; my $asc = shift; my $type = shift; my $idx = $cols_idx{$col}; print "idx: $idx\n"; my %subs = ( U => { a => sub { lc($a->[$idx]) cmp lc($b->[$idx]) }, n => sub { $a->[$idx] <=> $b->[$idx] }, s => sub { $a->[$idx] cmp $b->[$idx] }, }, D => { a => sub { lc($b->[$idx]) cmp lc($a->[$idx]) }, n => sub { $b->[$idx] <=> $a->[$idx] }, s => sub { $b->[$idx] cmp $a->[$idx] }, }, ); $subs{$asc}{$type}; } sub sort_maker { my @littlesubs = @_; sub { foreach my $sub (@littlesubs) { my $result = $sub->(); return $result if $result; } }; } sub sort_by_column { my $data = shift; my @order = @_; my $sortref = sort_maker( map { make_single_comparator( $data, $_, @{$parameters{$_}}) } + @order ); my @results = sort $sortref @$data; return [ @results ]; } __DATA__ HERNANDEZ HECTOR 456791 SAMSON 0217 2001-07-25 1963-08-0 +1 VASQUEZ JOAQUIN 456789 SAMSON 0209 1990-11-14 1970-03-2 +5 JONES TIMOTHY 803092 LAVER 0103 2001-03-19 1969-06-2 +9 SMITH BETTY_SUE 698389 SAMSON 0211 1992-01-23 1949-08-1 +2 VASQUEZ LEONARDO 456788 LAVER 0107 1990-08-23 1970-15-2 +3 SMITH HAROLD 359962 TRE 0111 2001-07-19 1973-10-0 +2 VASQUEZ ADALBERTO 786792 LAVER 0104 2001-07-26 1973-08-1 +7 VASQUEZ JORGE 456787 LAVER 0105 1986-01-17 1956-01-1 +3 VAZQUEZ TOMASINA 456790 LAVER 0110 1980-11-14 1960-14-0 +2 WILSON SYLVESTER 498703 LAVER 0110 1983-04-02 1953-06-2 +2 VASQUEZ ALBERTO 906786 TRE 0111 2001-07-15 1953-02-2 +8

The example I posted is a simplification of code that I've been using for years without problem and only in the last week discovered has a major bug. Your suggestions have given me ideas on how to fix that, and when I do I'll post the result. Thanks again.

jimk