Буквенно-цифровая или естественная сортировка ключей в хеше
У меня есть ключи в хэше следующим образом: AB3, AB1, AB2
и так далее. Я хотел бы отсортировать хэш по ключам. Как мне сделать это в Perl?
С этим связан вопрос, как отсортировать ключи так, чтобы буквы и цифры отображались в правильном порядке?
3 ответа
Вам нужно sort
функция:
foreach my $key ( sort keys %hash ) {
print "$key => $hash{$key}\n";
}
Вы не можете легко поддерживать хеши как отсортированные структуры, так как они просто не работают таким образом. Увидеть: perldata
больше о том, как работают хеши.
Редактировать: одна из тонкостей sort
в Perl, однако, это то, что он позволяет вам указать функцию. Эта функция должна занять $a
а также $b
и вернуться -1
, 0
, +1
в зависимости от того, если они до или после.
cmp
делает это для алфавита. <=>
делает это численно. И лучше всего, когда в сочетании с ||
Вы можете цепочки критериев, потому что -1
или же 1
"правда", но 0
ложно
Примерно так (например, заимствовал список ключей из другого поста для иллюстрации):
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my @keys = qw/ AB3 AB1 AB4
CD5 CD107 CB8
AC1 AC5 AC33
BA84 CB11 CA233/;
sub lex_num {
#split the keys into "word" and "digit" elements.
my @a_keys = $a =~ m/([A-Z]+)(\d+)/i;
my @b_keys = $b =~ m/([A-Z]+)(\d+)/i;
return ( $a_keys[0] cmp $b_keys[0]
|| $a_keys[1] <=> $b_keys[1] );
}
print join( "\n", sort lex_num @keys );
Это отсортирует первый бит по лексическому принципу, второй - по числовому. Если у вас больше комбинаций букв и цифр, это не сработает, но вы можете сделать, например, split
и for
петля.
Если ваши ключи определены не цифрами, за которыми следуют цифры, вы можете сделать:
my %h = (
CD45 => 4,
AB1 => 1,
AB22 => 3,
AB5 => 2,
);
sub mySort {
my ($xa,$ya) = $a =~ /^(\D+)(\d+)$/;
my ($xb,$yb) = $b =~ /^(\D+)(\d+)$/;
return -1 if $xa lt $xb;
return +1 if $xa gt $xb;
return $ya <=> $yb;
}
for (sort { mySort } keys %h) {
say "$_ => $h{$_}";
}
Выход:
AB1 => 1
AB5 => 2
AB22 => 3
CD45 => 4
Вот как вы можете объединить два подхода и сократить код с помощью модуля CPAN - в этом случае Sort::Naturally
(Я сделал хэш-ключи немного более сложными для иллюстративных целей):
use Sort::Naturally ;
my @keys = qw/ AB3 AB1 AB4
CD5 CD107 CB8
AC1 AC5 AC33
BA84 CB11 CA233/ ;
# make a hash from the keys with "whatever" as value:
my %hash;
%hash = map { $_ => $hash{$_} = 'whatever' } @keys ;
# Auto-magically naturally sort alphanumerically
# A module based approach to @Toto's solution:
for ( nsort keys %hash ) { print "$_ => $hash{$_} \n" };
Sobrique ответил базовым подходом perl к сортировке хеша по его ключам, а Toto показал, как вы можете сортировать эти ключи в указанном порядке, используя собственную подпрограмму в качестве аргумента в блоке. { }
следуя встроенным sort()
функция.
Рекомендации:
- Руководство по структурам данных Perl (см.
perldoc
perldsc
) - Perl FAQ по сортировке хэшей
- Как мне сохранить порядок ключей, которые я добавляю в хеш Perl?
- Почему хеш-ключи имеют другой порядок при печати?