Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have already read the documentation on sorting hashes by value, so please don't flame me. I am using activeperl 5.8 in a windows environment. When I try the imbedded sort, e.g.
foreach $k(sort {$match{$a}<=>$match{$b}} keys %match} I get an error, "Can't use "my $b" in sort comparison at D:\db\New\est +_keywords.pl line 41."
When I try the code below, it just returns a random unsorted list.
foreach $word(sort byval keys %match) { if ($match{$word} < 3) {next;} print "$word\t$match{$word}\n"; } } sub byval { return $match{$b} <=> $match{$a}; }
Help?

Replies are listed 'Best First'.
Re: Sorting by values doesn't work
by blokhead (Monsignor) on Jan 28, 2004 at 23:43 UTC
    From perldiag:
    Can't use "my %s" in sort comparison (F) The global variables $a and $b are reserved for sort co +mpar- isons. You mentioned $a or $b in the same line as the <=> +or cmp operator, and the variable had earlier been declared as a l +exical variable. Either qualify the sort variable with the packag +e name, or rename the lexical variable.
    This is why variable names of $a and $b are highly discouraged -- even when they are lexical, they can still indirectly interfere with sorting. Even when you split out the sorting subroutine, the variable names $a and/or $b are still bound to lexicals, not the global $a and $b (Perl just doesn't complain in this case). Thus the sort comparison returns the same thing every time, and your list still doesn't get sorted.

    blokhead

Re: Sorting by values doesn't work
by ysth (Canon) on Jan 29, 2004 at 00:08 UTC
    To add to what blokhead said, you need to make sure your sort routine is using the global (package) $a and $b instead of the lexical (my) $a and $b. You can do this several ways:
    • qualify as $::a and $::b in the sort. (Variables with :: are always globals; the empty package name is a synonym for the main package; If your sort() call is in package Foo, use $Foo::a and $Foo::b instead.)
    • restrict the scope of your lexical $a and $b to not include the sort.
    • put an our $a; our $b; before the sort. This will hide the lexicals until the end of the enclosing block. You can even put the our statements at the beginning of the sort routine (whether inline or not); this will cause a very slight slowdown, though.
    • rename your my $a and my $b to something else.
Re: Sorting by values doesn't work
by fireartist (Chaplain) on Jan 29, 2004 at 09:36 UTC
    It isn't the cause of the particular error message you mention, but the last character in your example is wrong. - It should be a round bracket, not curvy.
    foreach $k(sort {$match{$a}<=>$match{$b}} keys %match} ^ foreach $k(sort {$match{$a}<=>$match{$b}} keys %match) { }
    It's good to copy-and-paste code examples so that you don't introduce other errors in the re-typing.
Re: Sorting by values doesn't work
by Roger (Parson) on Jan 29, 2004 at 05:18 UTC
    Works for me... (ActivePerl 5.8.2):
    use strict; use warnings; my %match = ( 'A' => '1', 'B' => '5', 'C' => '9', 'D' => '8', 'E' => '2', ); foreach my $k (sort { $match{$a} <=> $match{$b} } keys %match) { print "$k - $match{$k}\n"; } foreach my $word(sort byval keys %match) { print "$word - $match{$word}\n"; } sub byval { return $match{$b} <=> $match{$a}; }

    And the output -
    A - 1 E - 2 B - 5 D - 8 C - 9 C - 9 D - 8 B - 5 E - 2 A - 1

    Can you show us more of your code because I believe the problem is related to something else in your code.