in reply to Sort by value - new twist

First, the following allow you to switch the procedure being called:

$sorter = \&my_sorter; foreach my $key (sort { &$sorter } keys %hash ) { # do something useful }

Update:

Because %hash is not necessarily scoped in my_sorter

Option 1

$sorter = \&my_sorter; foreach my $key (sort { &$sorter(\%hash) } keys %hash ) { # do something useful } sub my_sorter { my ($hashref) = @_; return $hashref->{$a} cmp $hashref->{$b}; }

Option 2

$sorter = \&my_sorter; foreach my $key ( map { $_->[0] } sort { &$sorter } map { [ $_, $hash{$_} ] } keys %hash ) { # do something useful } sub my_sorter { return $a->[1] cmp $b->[1]; }

Option 3

Use local %hash = %the_hash_to_process; before the foreach, and our %hash inside my_sorter.

There are more ways.

Replies are listed 'Best First'.
Re^2: Sort by value - new twist
by shemp (Deacon) on Sep 01, 2004 at 19:29 UTC
    Option 1 does it exactly!!!

    Brilliant!

      shemp,
      This is also how Tie::Hash::Sorted is able to dynamically change the sort routine. It can even sort via lexicals that the package normally wouldn't even be able to see via closures. If you could deal with your hash being tied, Tie::Hash::Sorted gives you the ability to define your sort routine at runtime for free.

      Cheers - L~R

Re^2: Sort by value - new twist
by ihb (Deacon) on Sep 02, 2004 at 01:44 UTC

    Regarding all options you propose: you need to handle that $a and $b is a package global if you want to have your sort routines elsewhere. IMHO, the easiest way to handle this is simply to pass them along in the function call. I.e. for option 1:

    my $sorter = \&my_sorter; foreach my $key (sort { $sorter->(\%hash, $a, $b) } keys %hash) { # do something useful } sub my_sorter { my ($hashref, $a, $b) = @_; return $hashref->{$a} cmp $hashref->{$b}; }

    You can do it by using caller and symbolic links, but I don't see any real benefit by that.

    ihb

    Read argumentation in its context!