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

All depends on how abstract you want to get. Given that you want "the keyboard operator [to be able to] modify it easily," I'd say that you may want it as abstract as possible.

#!/usr/bin/perl use strict; use warnings; 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 ) ], ); 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 { $a->[$idx] cmp $b->[$idx] }, n => sub { $a->[$idx] <=> $b->[$idx] }, # s??? not sure what you mean by 's' ... feel fre +e to # modify this. 's' => sub { $a->[$idx] cmp $b->[$idx] }, }, D => { a => sub { $b->[$idx] cmp $a->[$idx] }, n => sub { $b->[$idx] cmp $a->[$idx] }, # same problem as above. 's' => sub { $b->[$idx] cmp $a->[$idx] }, }, ); $subs{$asc}{$type}; } sub sort_maker { my @subs = @_; sub { foreach my $sub (@subs) { my $result = $sub->(); # you use $a and $b in your littles +ubs - no need to pass in globals. 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; @results } my @data = map [ split " " ] => <DATA>; use Data::Dumper; print Dumper [sort_by_column(\@data, @ARGV ? @ARGV : qw{ lastname firs +tname cno } )]; __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

As you notice, much of the error checking (that parms are actually allowed - e.g., 'foo' isn't a table header) is missing. Feel free to add.

Also, rather than a big hash, you could build it up using an eval STRING. Up to you - I'm using a large closure instead to probably reduce memory, probably reduce runtime, and definitely reduce the ability for me to screw it up security-wise. That said, I do think that this is probably a scenario that could be made secure for an eval STRING, especially if you start getting many more options on how to do things and those start combining to give exponential degrees of freedom. Here there are only six possible comparators, which is easy enough to hardcode ahead of time. More generically, an eval STRING may ease development and maintenance.

Replies are listed 'Best First'.
Re^6: Building a sorting subroutine on the fly
by jkeenan1 (Deacon) on Nov 30, 2005 at 00:54 UTC
    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:

    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

Re^6: Building a sorting subroutine on the fly
by jkeenan1 (Deacon) on Dec 31, 2005 at 03:27 UTC
    I promised to post the code for which I was seeking assistance once I had the project completed. Here it is, taken from CPAN module Data::Presenter, version 1.02:

    Thanks again, tanktalus and brian.

    Jim Keenan