按字母数字排序对哈希键进行排序

use*_*bio 1 sorting perl hash alphanumeric

我刚刚阅读了在 Perl 中排序字母数字哈希键的帖子. 但是我是从 Perl 开始的,我不是很清楚。

所以我有一个这样的哈希:

  %hash = (
        "chr1" => 1,
        "chr2" => 3,
        "chr19" => 14,
        "chr22" => 1,
        "X" => 2,
    )
Run Code Online (Sandbox Code Playgroud)

我试图获得这样的输出:

chr1
chr2
chr19
chr22
Run Code Online (Sandbox Code Playgroud)

但我正在获得这样的输出:

chr1
chr19
chr2
chr22
Run Code Online (Sandbox Code Playgroud)

我写了这段代码,但它创建了上面的错误输出:

foreach my $chr (sort {$a cmp $b} keys(%hash)) {
    my $total= $hash{$chr};
    my $differentpercent= ($differenthash{$chr} / $total)*100;
    my $round=(int($differentpercent*1000))/1000;
    print "$chr\t$hash{$chr}\t$differenthash{$chr}\t$round\n";
}
Run Code Online (Sandbox Code Playgroud)

它打印:

chr1    342421    7449    2.175
chr10    227648    5327    2.34
chr11    220415    4468    2.027
chr12    213263    4578    2.146
chr13    172379    3518    2.04
chr14    143534    2883    2.008
chr15    126441    2588    2.046
chr16    138239    3596    2.601
chr17    122137    3232    2.646
chr18    130275    3252    2.496
chr19    99876    2836    2.839
chr2    366815    8123    2.214
Run Code Online (Sandbox Code Playgroud)

我怎样才能解决这个问题?

Bor*_*din 5

更新注释@Miller 在下面对该Sort::Naturally模块的一些缺点的评论。

您要求的是一种相对复杂的排序,它将每个字符串拆分为字母和数字字段,然后按词法对字母和数字进行排序。

该模块Sort::Naturally将按照您的要求执行,或者您可以编写类似的内容。您似乎忽略了该X键,因此我使用独立于大小写的排序将其排序到最后。

use strict;
use warnings;

my %hash = map { $_ => 1 } qw(
    chr22  chr20  chr19  chr13  chr21  chr16  chr12  chr10  chr18
    chr17  chrY   chr5   chrX   chr8   chr14  chr6   chr3   chr9
    chr1   chrM   chr11  chr2   chr7   chr4   chr15
);

my @sorted_keys = sort {
    my @aa = $a =~ /^([A-Za-z]+)(\d*)/;
    my @bb = $b =~ /^([A-Za-z]+)(\d*)/;
    lc $aa[0] cmp lc $bb[0] or $aa[1] <=> $bb[1];
} keys %hash;

print "$_\n" for @sorted_keys;
Run Code Online (Sandbox Code Playgroud)

输出

chr1
chr2
chr3
chr4
chr5
chr6
chr7
chr8
chr9
chr10
chr11
chr12
chr13
chr14
chr15
chr16
chr17
chr18
chr19
chr20
chr21
chr22
chrM
chrX
chrY
Run Code Online (Sandbox Code Playgroud)

使用Sort::Naturally模块(您可能必须安装它),您可以改为编写它。

use strict;
use warnings;

use Sort::Naturally;

my %hash = map { $_ => 1 } qw(
    chr22  chr20  chr19  chr13  chr21  chr16  chr12  chr10  chr18
    chr17  chrY   chr5   chrX   chr8   chr14  chr6   chr3   chr9
    chr1   chrM   chr11  chr2   chr7   chr4   chr15
);

my @sorted_keys = nsort keys %hash;

print "$_\n" for @sorted_keys;
Run Code Online (Sandbox Code Playgroud)

输出与上述相同。

  • @米勒:当然。我总是使用标准排序,除非它被证明太慢了。即使我最终缓存了排序键(除了 ST 之外,还有很多方法可以做到这一点)我通常将原始排序代码放在旁边以记录它*真正*在做什么,因为它远非立即显而易见正在排序施瓦兹变换。 (2认同)
  • @Borodin 我强烈建议将此模块推荐切换为 [`Sort::Key::Natural`](https://metacpan.org/pod/Sort::Key::Natural)。`Sort::Naturally` 中存在一些错误,它忽略标点符号而只查找字母和数字组之间的交替。例如,对于这个数据 `qw(124:8 17:11);`,它会在 17 之前对 124 进行排序,因为在内部它会去掉冒号,然后将它们按数字排序为单个数字。 (2认同)