Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Perl,how do you sort a lexical hash by its value with a dedicated subroutine?

Tags:

sorting

perl

This works:

my %score = ( a => 1, b => 2);
@keys = sort {$score{$a} <=> $score{$b}} keys %score;

But how can I put the code inside {..} to a dedicated sub routine?

sub by_num {
  $score{$a} <=> $score{$b}
}

@keys = sort by_num keys %score;

?

like image 329
new_perl Avatar asked Jan 20 '26 19:01

new_perl


2 Answers

The main problem here is having a subroutine that has access to the hash. You either have to create one function per hash you want to sort:

#!/usr/bin/perl

use strict;
use warnings;

{
    my %hash = (
        a => 1,
        b => 2,
        c => 3,
    );

    sub sort_hash_a {
        return $hash{$a} <=> $hash{$b};
    }

    for my $k (sort sort_hash_a keys %hash) {
        print "$k\n";
    }
}

{
    my %hash = (
        x => 1,
        y => 2,
        z => 3,
    );

    sub sort_hash_b {
        return $hash{$a} <=> $hash{$b};
    }

    for my $k (sort sort_hash_b keys %hash) {
        print "$k\n";
    }
}

Or create a higher-order function that creates the functions for you:

#!/usr/bin/perl

use strict;
use warnings;

sub make_hash_sort {
    my $hashref = shift;

    return sub {
        return $hashref->{$a} <=> $hashref->{$b};
    };
}

my %hash = (
    one   => 1,
    two   => 2,
    three => 3,
);

my $sub = make_hash_sort \%hash;

for my $k (sort $sub keys %hash) {
    print "$k\n";
}

But all of that is, generally, wasted effort for both the programmer and the computer. The block syntax is faster and easier to use in almost all cases. The only exceptions would be complicated sorts or highly repetitive code.

like image 130
Chas. Owens Avatar answered Jan 23 '26 10:01

Chas. Owens


A hash produces a list of key/value pairs in list context; you're then using the values as keys, and there is no e.g. $score{90}. Use keys %score to get just the keys.

like image 34
geekosaur Avatar answered Jan 23 '26 10:01

geekosaur