It seems there are several issues here. First, assume it's unknown at script development time how many search criteria will be used. Second, assume that at script development time it is unknown whether a particular sort criteria will be numeric or string-based. And third, assume that it is unknown at script development time what the order of precedence will be for the various sort criteria.
It struck me that it might be clever to build up a string representation of the multi-criteria sort routine at runtime, when the desired criteria are known. Then one can eval the routine, sort and all, to gain the desired result. Here is what I came up with:
use strict; use warnings; # Name Sex Age IQ Hair Eyes my %hash = ( 'Lisa' => [ 'F', 6, 150, 'Blonde', 'Blue' ], 'Homer' => [ 'M', 40, 105, 'Bald', 'Blue' ], 'Bart' => [ 'M', 9, 120, 'Blonde', 'Brown' ], 'Marge' => [ 'F', 36, 135, 'Blue', 'Blue' ], 'Maggie' => [ 'F', 1, 130, 'Blonde', 'Blue' ] ); # Assume that @criteria is actually obtained at runtime. my @criteria = ( 0, 2, 3 ); my @comparisons; my ( $sample_key, $sample_value ) = each %hash; foreach ( @criteria ) { push @comparisons, "\$hash{\$a}[$_]" . ( $sample_value =~ /^\d+$/ ? " <=> " : " cmp " ) . " \$hash{\$b}[$_]"; } my $routine = join " || ", @comparisons; my @sorted; eval "\@sorted = sort { $routine } keys \%hash" or die "Ick!\n$@\n"; print $_, "\n" foreach @sorted; __OUTPUT__ Maggie Marge Lisa Homer Bart
This method just builds up a sort routine by creating an array of comparison criteria, and joining them together with " || " logical short circuits. The logical short circuit causes the secondary and terciary (etc) criteria to be evaluated if the primary (and so on) criteria evaluate to equality. Using a logical short circuit inside a sort routine is a pretty common idiom. I just worked out one way of allowing the criteria list to be built at runtime.
The resulting sort routine string is interpolated into an eval expression that already contains the necessary skelleton to implement a sort of a hash's keys. What I have intentionally avoided (to reduce complexity) is the necessary logic to allow for dynamic selection of $b<=>$a versus $a<=>$b ordering. It would be possible to allow for that, but to keep this illustration more to the point I glossed over that extra logic.
If anyone else has come up with a more flexible and robust way of creating a sort routine with runtime selected criteria I'd be interested in reading about it here too.
Dave
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Fun with complex sorting on arbitrary criteria list.
by tilly (Archbishop) on Feb 01, 2004 at 10:44 UTC | |
|
Re: Fun with complex sorting on arbitrary criteria list.
by stvn (Monsignor) on Feb 01, 2004 at 22:01 UTC | |
|
Re: Fun with complex sorting on arbitrary criteria list.
by simonm (Vicar) on Feb 01, 2004 at 17:05 UTC | |
|
Re: Fun with complex sorting on arbitrary criteria list.
by parv (Parson) on Feb 01, 2004 at 09:48 UTC |