使用多个条件对嵌套哈希进行排序

Fer*_*ves 1 perl hash multidimensional-array protein-database perl-hash

我对 perl 编程有点陌生,我有一个可以这样表述的散列:

$hash{"snake"}{ACB2}   = [70, 120];
$hash{"snake"}{SGJK}   = [183, 120];
$hash{"snake"}{KDMFS}   = [1213, 120];
$hash{"snake"}{VCS2}   = [21, 120];
...
$hash{"bear"}{ACB2}   = [12, 87];
$hash{"bear"}{GASF}   = [131, 87];
$hash{"bear"}{SDVS}   = [53, 87];
...
$hash{"monkey"}{ACB2}   = [70, 230];
$hash{"monkey"}{GMSD}   = [234, 230];
$hash{"monkey"}{GJAS}   = [521, 230];
$hash{"monkey"}{ASDA}   = [134, 230];
$hash{"monkey"}{ASMD}   = [700, 230];
Run Code Online (Sandbox Code Playgroud)

哈希的结构总结如下:

%hash{Organism}{ProteinID}=(protein_length, total_of_proteins_in_that_organism)
Run Code Online (Sandbox Code Playgroud)

我想根据某些条件对这个哈希进行排序。首先,我只想考虑那些蛋白质总数大于100的生物,然后我想显示生物的名称以及最大的蛋白质及其长度。

为此,我将采用以下方法:

    foreach my $org (sort keys %hash) {
        foreach my $prot (keys %{ $hash{$org} }) {
            if ($hash{$org}{$prot}[1] > 100) {
                @sortedarray = sort {$hash{$b}[0]<=>$hash{$a}[0]} keys %hash;

                print $org."\n";
                print @sortedarray[-1]."\n";
                print $hash{$org}{$sortedarray[-1]}[0]."\n"; 
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

但是,这会打印出与蛋白质总数一样多的生物体名称,例如,它会打印 120 次“snake”。此外,这不是正确排序,因为我想我应该在排序行中使用变量 $org 和 $prot。

最后,输出应如下所示:

snake
"Largest protein": KDMFS [1213]

monkey
"Largest protein": ASMD [700]
Run Code Online (Sandbox Code Playgroud)

zdi*_*dim 5

所有数据按打印排序

use warnings;
use strict;
use feature 'say';

use List::Util qw(max);

my %hash;   
$hash{"snake"}{ACB2}   = [70, 120];
$hash{"snake"}{SGJK}   = [183, 120];
$hash{"snake"}{KDMFS}   = [1213, 120];
$hash{"snake"}{VCS2}   = [21, 120];
$hash{"bear"}{ACB2}   = [12, 87];
$hash{"bear"}{GASF}   = [131, 87];
$hash{"bear"}{SDVS}   = [53, 87];    
$hash{"monkey"}{ACB2}   = [70, 230];
$hash{"monkey"}{GMSD}   = [234, 230];
$hash{"monkey"}{GJAS}   = [521, 230];
$hash{"monkey"}{ASDA}   = [134, 230];
$hash{"monkey"}{ASMD}   = [700, 230];

my @top_level_keys_sorted = 
    sort {   
        ( max map { $hash{$b}{$_}->[0] } keys %{$hash{$b}} ) <=> 
        ( max map { $hash{$a}{$_}->[0] } keys %{$hash{$a}} )
    }   
    keys %hash;

for my $k (@top_level_keys_sorted) {
    say $k; 
    say "\t$_ --> @{$hash{$k}{$_}}" for 
        sort { $hash{$k}{$b}->[0] <=> $hash{$k}{$a}->[0] } 
        keys %{$hash{$k}};
}
Run Code Online (Sandbox Code Playgroud)

根据要求,这首先按 arrayref 值中的第一个数字对顶级键进行排序。有了这个排序的键列表,我们然后进入每个键的 hashref 并进一步排序。该循环是我们根据需要调整以限制输出的内容(前 100 个按总数计算,仅按长度计算最大,等等)。

它打印

蛇
        KDMFS --> 1213 120
        SGJK --> 183 120
        ACB2 --> 70 120
        VCS2 --> 21 120
猴
        ASMD --> 700 230
        GJAS --> 521 230
        GMSD --> 234 230
        ASDA --> 134 230
        ACB2 --> 70 230
熊
        GASF --> 131 87
        SDVS --> 53 87
        ACB2 --> 12 87

我不知道输出是应该显示所有“蛋白质总数高于 100 的生物体”(文本)还是只显示最大的一个(期望输出),所以我将全部保留。根据需要切断。要仅获得最大的一个,要么比较循环中每个键的最大值,要么查看这篇文章(同样的问题)。

请注意,散列本身不能“排序”,因为它本质上是无序的。但是我们可以像上面一样打印出排序的东西,或者生成可以排序的辅助数据结构,如果需要的话。