В Perl, как вы сортируете лексический хеш по его значению с помощью специальной подпрограммы? - PullRequest
2 голосов
/ 04 июля 2011

Это работает:

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

Но как я могу поместить код внутри {..} в отдельную подпрограмму?

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

@keys = sort by_num keys %score;

Ответы [ 6 ]

5 голосов
/ 04 июля 2011

Основная проблема заключается в наличии подпрограммы, которая имеет доступ к хешу. Вы должны либо создать одну функцию для каждого хэша, который хотите отсортировать:

#!/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";
    }
}

Или создайте функцию более высокого порядка, которая создаст функции для вас:

#!/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";
}

Но все это, как правило, напрасная трата и для программиста, и для компьютера. Синтаксис блока быстрее и проще в использовании почти во всех случаях. Единственными исключениями могут быть сложные сортировки или повторяющийся код.

2 голосов
/ 04 июля 2011

Хеш создает список пар ключ / значение в контексте списка;затем вы используете значения в качестве ключей, а нет, например, $score{90}.Используйте keys %score, чтобы получить только ключи.

1 голос
/ 04 июля 2011

Пример передачи процедуры сортировки как ключа, так и значения, требующей некоторых манипуляций как до, так и после сортировки:

sub sordid {
    $a->[1] <=> $b->[1];
}

my %score = ( a => 1, b => 2 );
@keys = map $_->[0], sort sordid map [ $_ => $score{$_} ], keys %score;

или с использованием альтернативного типа передачи элементов (запускается по прототипу):

sub sordid($$) {
    $_[0][1] <=> $_[1][1];
}

my %score = ( a => 1, b => 2 );
@keys = map $_->[0], sort sordid map [ $_ => $score{$_} ], keys %score;

(Это необходимо для процедур сортировки, предназначенных для вызова из других пакетов, поскольку $ a и $ b являются переменными пакета в пакете, где вызывается сортировка.)

1 голос
/ 04 июля 2011

С закрытием!

sub hashsort {
  my %hash = @_;
  return sub { $hash{$a} <=> $hash{$b}; }
}

my $sorter = hashsort(%hash);
@keys = sort $sorter keys %hash;

Должен работать.И нет, он никогда не будет "переделывать %hash при каждом вызове", потому что hashsort будет вызываться только один раз, а возвращаемая функция будет вызываться повторно.Хотя с учетом все менее привлекательного синтаксиса вы можете абстрагировать все это в функцию, то есть

sub sortkeys (\%) {
  my $hash = shift;
  return sort { $hash->{$a} <=> $hash->{$b} } keys %$hash;
}

@keys = sortkeys %hash;

Вы можете предпочесть версию без прототипа и передать хеш как ссылку вручную (или не как ссылкуна все).

0 голосов
/ 10 июля 2013

Пример сортировки в ASC и DESC:

    use strict;

    my %hash = (
        four   => 4,
        one   => 1,
        two   => 2,
        five   => 5,
        three => 3,
    );


    my $sub_asc = make_hash_sort(\%hash,'asc');

    print "--- ASC ---\n";
    for my $k (sort $sub_asc keys %hash) {
        print "$k\t\t$hash{$k}\n";
    }


my $sub_desc = make_hash_sort(\%hash,'desc');

print "\n--- DESC ---\n";
for my $k (sort $sub_desc keys %hash) {
    print "$k\t\t$hash{$k}\n";
}



###  Sort hash by value
sub make_hash_sort {
    my ($hashref, $how) = @_;
    return sub {
        if ($how eq 'asc') {
            return $hashref->{$a} <=> $hashref->{$b};
        } elsif ($how eq 'desc') {
            return $hashref->{$b} <=> $hashref->{$a};
        }
    };
}
0 голосов
/ 04 июля 2011

Не переоценивайте это, если вы хотите отсортировать по номеру, просто сделайте это:

%score = ( a => 1, b => 2);

sub keys_sorted_by_num {
  my %h = @_;
  return sort {$h{$a} <=> $h{$b}} keys %h;
}

@keys = keys_sorted_by_num %score;

Меньше волшебства делает для более ясного кода ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...