Sentinel has asked for the wisdom of the Perl Monks concerning the following question:
I'm writing a simple database-type application in which the data needs to be sorted by whichever column the user selects. I'm having trouble figuring out a way to dynamically determine which sort algorithm to use in the main "sort" statement. I'm maintaining the session state, including the variable $sortname, which contains the name of the function containing the appropriate sort function.
If the user wants to sort the data in descending order by the "FirstName" column, $sortname contains "firstname_descending". This would seem useful, since I can say the following:
my @order = sort firstname_descending keys %data;
However, what I WANT to use is:
my @order = sort $sortname keys %data;
That way, if $sortname contains "firstname_descending", this function would still be called:
sub firstname_descending {
$data{$b}{'FirstName'} cmp $data{$a}{'FirstName'};
}
Why doesn't that work? How can I use this type of sort architecture?
RE: Dynamic sort algorithm selection
by btrott (Parson) on Nov 15, 2000 at 05:46 UTC
|
What version of Perl are you using? This works for
me:
#!/usr/bin/perl -w
use strict;
my $sortname = shift;
print join ' ', sort $sortname 1..20;
sub num { $a <=> $b }
sub alpha { $a cmp $b }
Save this as foo.pl, and...
% foo.pl num
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
% foo.pl alpha
1 10 11 12 13 14 15 16 17 18 19 2 20 3 4 5 6 7 8 9
This is consistent w/ the sort docs:
SUBNAME may be a scalar variable name
(unsubscripted), in which case the value provides
the name of (or a reference to) the actual subroutine
to use. In place of a SUBNAME, you can provide a
BLOCK as an anonymous, in-line sort
subroutine.
However, I do seem to remember running into
your situation in the past. I don't know what version
of Perl I was using then; probably 5.004 or some
such. I'm now using 5.005_03, which could
explain it.
If you are using a real database, though, I would
suggest that you try using "order by", as it's likely
to be faster than anything you can do yourself,
particularly if you have your columns indexed. | [reply] [d/l] [select] |
RE (tilly) 1: Dynamic sort algorithm selection
by tilly (Archbishop) on Nov 15, 2000 at 05:58 UTC
|
use Carp; # So we can get verbose error messages
# Time passes
sub ret_str_sorter {
my $field = shift;
my $direction = shift;
if ('ascending' eq $direction) {
return sub {
$data{$a}{$field} cmp $data{$b}{$field};
};
}
elsif ('descending' eq $direction) {
return sub {
$data{$b}{$field} cmp $data{$a}{$field};
};
}
else {
confess("Direction '$direction' not understood");
}
}
# Time passes
my $sorter = ret_str_sorter($field, $direction);
my @ordered = sort $sorter keys %data;
ObRandomTip: Rather than working with an array of keys into
a hash, instead restructure to have an array of anonymous
hashes. This will generally lead to a cleaner design and
no need to do things like pass the hash definition in
through a global. | [reply] [d/l] |
RE: Dynamic sort algorithm selection
by quidity (Pilgrim) on Nov 15, 2000 at 05:42 UTC
|
This does actually work the way you expected, set up some subs with known names, then give the sort routine a variable containing that name:
sub ascii {$a cmp $b}
sub alpha {lc($a) cmp lc($b)}
@a = qw(a A b B D d c C);
$subname = 'ascii';
@sorted = sort $subname @a;
print @sorted;
$subname = 'alpha';
@sorted = sort $subname @a;
print @sorted;
If you are having trouble with an earlier version of perl, then first try upgrading, failing that, you can always use eval:
eval '@sorted = sort ' . $subname . ' @unsorted';
But that's icky, so try not to do that. | [reply] [d/l] [select] |
RE: Dynamic sort algorithm selection
by dchetlin (Friar) on Nov 15, 2000 at 05:53 UTC
|
That should work just fine as you have it (and has worked that way as far back as 5.004, at least). You can have the
name of the subroutine in the scalar passed to sort.
Not only that, but you can go one better. You can pass sort
a reference to a subroutine. This is safer and cleaner and faster
than using the name of the sub.
my $sortref = \&firstname_descending;
my @order = sort $sortref keys %data;
For best results, combine this approach with a dispatch table
that does your subroutine lookup.
-dlc | [reply] [d/l] |
RE: Dynamic sort algorithm selection
by Fastolfe (Vicar) on Nov 15, 2000 at 19:10 UTC
|
I might implement that something like this:
%SORT_INFO = (
'firstname' => sub { $a->{FirstName} cmp $b->{FirstName} },
'firstname_desc => sub { $b->{FirstName} cmp $a->{FirstName} },
...
);
...
if (exists $SORT_INFO{param('sort_by')}) {
@sorted = sort $SORT_INFO{param('sort_by')} @unsorted;
} elsif (param('sort_by')) {
die "Unknown sort_by item: " . param('sort_by');
} else {
@sorted = @unsorted;
}
| [reply] [d/l] |
Re: Dynamic sort algorithm selection
by Sentinel (Initiate) on Nov 16, 2000 at 14:09 UTC
|
The problem with my situation was simple, and no one thought of it or caught it, including me. I had
use strict;
in effect, which includes
use strict 'refs';
No dice on the sort subroutine's reference under those conditions. Sorry for the turmoil. I'll go back into my hole in the wall now. | [reply] [d/l] [select] |
RE: Dynamic sort algorithm selection
by jptxs (Curate) on Nov 15, 2000 at 07:15 UTC
|
Being a Database bigot, I point out to you that almost every RDBMS has a sort mechanism, and you night want to let the Database do the sorting. Just a thought.
<myExperience>
$mostLanguages = 'Designed for engineers by engineers.';
$perl = 'Designed for people who speak by a linguist.';
</myExperience>
| [reply] [d/l] |
RE: Dynamic sort algorithm selection
by brick (Sexton) on Nov 15, 2000 at 07:35 UTC
|
So basically you want a pointer to a function.
I'm not too sure how to do that..I know that you
can create/use pointers within perl, but I haven't
dug through my tchrist notes in too long to even
have a clue of remembering how.
As far as making pointers to functions...couldn't
you just make a simple if/else or case based on the
designation variable to avoid the whole headache?
TIMTOWTDI, and all that, I guess.
What algorithm are you looking to use for your
array sort? The first glance made it look like a
bubble sort, which is fine if you aren't trying for
high performance. Otherwise, _Algorithms and Data
Structures_ by Corman-- aka the white cookbook, is
a good place to get a lot of non-language specific
psuedocode for just about every basic sorting option.
good luck, -B. | [reply] |
|
| [reply] |
|
That's cool...I'm not looking to start a pissing
contest, but the question didn't have any replies
when I started my post, so I didn't have the
benefit of your code.
As far as the difference between a pointer and a
reference...dude, when it comes down to it, aren't
they really just the same thing? Semantically, yes,
they're different. Under the hood? I pass things by
reference, I give you the address. I use a pointer,
it holds the address of something. I make a reference
and I point you to a seperate chunk of code. I'm not
a complete chimp on that respect. I haven't had the
time or inclination to go look at whether or not the
interpreter makes full substitutions at references or
jumps to the sub when everything's said and done.
That's deeper than I've needed to be for a long time.
I _am_ an Acolyte, though, and one who does not get to
code nearly as much as he wants to, so it is my bad
for missing the pretty obvious reference to the
native sort. I shouldn't have done that. I've always
had that inherent distrust of someone else's code that
I haven't thoroughly looked examined, just a leftover
from school, and that's why I made the comment about
picking a sorting algorithm. I know those ingrown ones
are usually good at large data sets, but I like to pull
off the lid and see _exactly_ how it's working inside,
make sure it fits. You can't blame a guy for that.
ever learning,
-B.
| [reply] |
|
|
|
|