Как мне отсортировать хэш хэшей по ключу в Perl? - PullRequest
6 голосов
/ 13 апреля 2009

Я хочу отсортировать хеш, который на самом деле имеет хеш в качестве значения. Например:

my %hash1=(
   field1=>"",
   field2=>"",
   count=>0,
);
my %hash2;
$hash2{"asd"}={%hash1};

и я вставил множество хэшей в %hash2 с различными значениями счетчика %hash2.

Как мне отсортировать %hash1 в соответствии со значением счетчика hash1?

Есть ли способ сделать это без применения быстрой сортировки вручную, например, с помощью функции сортировки Perl?

Ответы [ 5 ]

10 голосов
/ 13 апреля 2009
my @hash1s = sort {$a->{count} <=> $b->{count}} values %hash2;
6 голосов
/ 13 апреля 2009

С perlfaq4 , ответ на "http://faq.perl.org/perlfaq4.html#How_do_I_sort_a_hash" содержит большую часть информации, которая необходима вам для составления кода.

Возможно, вы захотите увидеть главу о сортировке в Изучение Perl .

У Криса совершенно хороший ответ, хотя я ненавижу использовать values таким образом. Более привычный способ сделать то же самое - это просмотреть ключи хэша верхнего уровня, но отсортировать по ключу второго уровня:

my @sorted_hashes = 
    sort { $hash2->{$a}{count} <=> $hash2->{$b}{count} } 
    keys %hash2;

Я делаю это так, потому что это немного менее изнурительно.


Как отсортировать хеш (необязательно по значению вместо ключа)?

(предоставлено Брайаном Д. Фой)

Чтобы отсортировать хеш, начните с ключей. В этом примере мы даем список ключей для функции сортировки, которая затем сравнивает их ASCIIbetically (на что могут повлиять ваши настройки локали). Список вывода имеет ключи в ASCIIbetical порядке. После того, как у нас есть ключи, мы можем просмотреть их, чтобы создать отчет, в котором перечислены ключи в порядке ASCII.

my @keys = sort { $a cmp $b } keys %hash;

foreach my $key ( @keys )
    {
    printf "%-20s %6d\n", $key, $hash{$key};
    }

Мы могли бы получить больше фантазии в блоке sort (). Вместо того, чтобы сравнивать ключи, мы можем вычислить значение с ними и использовать это значение для сравнения.

Например, чтобы сделать наш порядок отчетов без учета регистра, мы используем последовательность \ L в строке в двойных кавычках, чтобы сделать все строчными. Затем блок sort () сравнивает значения в нижнем регистре, чтобы определить, в каком порядке следует помещать ключи.

my @keys = sort { "\L$a" cmp "\L$b" } keys %hash;

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

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

my @keys = sort { $hash{$a} <=> $hash{$b} } keys %hash;

Оттуда мы можем стать более сложными. Если значения хеша совпадают, мы можем предоставить вторичную сортировку для ключа хеша.

my @keys = sort {
    $hash{$a} <=> $hash{$b}
        or
    "\L$a" cmp "\L$b"
    } keys %hash;
1 голос
/ 13 апреля 2009

Если вы хотите получить список хэшей (например, hash1), отсортированный по количеству значений в hash2, это может помочь:

@sorted_hash1_list = sort sort_hash_by_count_key($a, $b) (values (%hash2);


# This method can have any logic you want
sub sort_hash_by_count_key {
    my ($a, $b) = @_;
    return $a->{count} <=> $b->{count};
}
0 голосов
/ 01 июня 2012

Для сортировки по цифрам используйте <=>, а для строк - cmp.

# sort by the numeric count field on inner hash
#
foreach my $key (sort {$hash2{$a}->{'count'} <=> $hash2{$b}->{'count'}} keys %hash2) {
   print $key,$hash2{$key}->{'count'},"\n";
}

# sort by the string field1 (or field2) on the inner hash
#
foreach my $key (sort {$hash2{$a}->{'field1'} cmp $hash2{$b}->{'field1'}} keys %hash2) {
   print $key,$hash2{$key}->{'field1'},"\n";
}

Чтобы изменить порядок, просто поменяйте местами $ a и $ b:

# sort by the numeric count field on inner hash
#
foreach my $key (sort {$hash2{$a}->{'count'} <=> $hash2{$b}->{'count'}} keys %hash2) {
   print $key,$hash2{$key}->{'count'},"\n";
}

# sort by the string field1 (or field2) on the inner hash
#
foreach my $key (sort {$hash2{$a}->{'field1'} cmp $hash2{$b}->{'field1'}} keys %hash2) {
   print $key,$hash2{$key}->{'field1'},"\n";
}
0 голосов
/ 13 апреля 2009

См. http://perldoc.perl.org/functions/sort.html, где много контекста, как сортировка работает в Perl.

А вот пример .. пытаюсь быть читаемым, а не перлы.

#!/usr/bin/perl
# Sort Hash of Hashes by sub-hash's element count.
use warnings;
use strict;


my $hash= {
            A=>{C=>"D",0=>"r",T=>"q"}
           ,B=>{}
           ,C=>{E=>"F",G=>"H"}
          };

sub compareHashKeys {0+(keys %{$hash->{$a}}) <=> 0+(keys %{$hash->{$b}}) }

my @SortedKeys = sort compareHashKeys keys %{$hash};
print join ("," , @SortedKeys) ."\n";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...