1

我对 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];

哈希的结构总结如下:

%hash{Organism}{ProteinID}=(protein_length, total_of_proteins_in_that_organism)

我想根据某些条件对这个哈希进行排序。首先,我只想考虑那些蛋白质总数高于 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"; 
            }
        }
    }

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

最后,输出应如下所示:

snake
"Largest protein": KDMFS [1213]

monkey
"Largest protein": ASMD [700]
4

4 回答 4

4

所有数据在打印中排序

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}};
}

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

它打印

蛇
        KDMFS --> 1213 120
        新加坡--> 183 120
        ACB2 --> 70 120
        VCS2 --> 21 120
猴
        ASMD --> 700 230
        GJAS --> 521 230
        GMSD --> 234 230
        阿斯达 --> 134 230
        ACB2 --> 70 230
熊
        天然气-> 131 87
        SDVS --> 53 87
        ACB2 --> 12 87

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

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

于 2019-11-22T08:28:23.947 回答
1

您可以使用List::Util reduce来获得每个生物体的最大值。

我意识到你可能不熟悉 List::Util 中的这个函数,但对于这个问题的例子,它非常简单。

保存数据的结构的组成是数组的散列,其中有机体作为键,整行存储在数组引用中作为散列的值。

数据结构的选择部分取决于所需输出的形式。

#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw/reduce/;

use constant {org_idx => 0, prot_idx => 1, len_idx => 2, cnt_idx => 3};

my %stuff;

while (<DATA>) {
    chomp;
    my @data = split /,/;

    # saving all 4 items (per line)
    # key is the organism
    push @{$stuff{$data[org_idx]}}, \@data; 
}

for my $org (sort keys %stuff) {
    my $aref = $stuff{$org}; # an array of arrays reference

    # to find the record with the max length
    # $max becomes an array reference containing all 4 of the items as a list
    my $max = reduce{$a->[len_idx] > $b->[len_idx] ? $a : $b} @$aref;

    next if $max->[cnt_idx] < 100;

    print $org, "\n";
    print "Largest protein: $max->[prot_idx] [$max->[len_idx]]\n";
}



__DATA__
snake,ACB2,70,120
snake,SGJK,183,120
snake,KDMFS,1213,120
snake,VCS2,21,120
bear,ACB2,12,87
bear,GASF,131,87
bear,SDVS,53,87
monkey,ACB2,70,230
monkey,GMSD,234,230
monkey,GJAS,521,230
monkey,ASDA,134,230
monkey,ASMD,700,230

印刷

monkey
Largest protein: ASMD [700]
snake
Largest protein: KDMFS [1213]

数据::自卸车%stuff

$VAR1 = {
          'monkey' => [
                        [
                          'monkey',
                          'ACB2',
                          70,
                          '230'
                        ],
                        [
                          'monkey',
                          'GMSD',
                          234,
                          '230'
                        ],
                        [
                          'monkey',
                          'GJAS',
                          521,
                          '230'
                        ],
                        [
                          'monkey',
                          'ASDA',
                          134,
                          '230'
                        ],
                        [
                          'monkey',
                          'ASMD',
                          700,
                          '230'
                        ]
                      ],
          'bear' => [
                      [
                        'bear',
                        'ACB2',
                        12,
                        '87'
                      ],
                      [
                        'bear',
                        'GASF',
                        131,
                        '87'
                      ],
                      [
                        'bear',
                        'SDVS',
                        53,
                        '87'
                      ]
                    ],
          'snake' => [
                       [
                         'snake',
                         'ACB2',
                         70,
                         '120'
                       ],
                       [
                         'snake',
                         'SGJK',
                         183,
                         '120'
                       ],
                       [
                         'snake',
                         'KDMFS',
                         1213,
                         '120'
                       ],
                       [
                         'snake',
                         'VCS2',
                         21,
                         '120'
                       ]
                     ]
        };
于 2019-11-22T23:45:04.800 回答
1

你正在用吗

use strict;
use warnings;

在脚本的开头?这样至少会突出一些问题的根源。没有它们,Perl 会默默地做一些很容易被指出为愚蠢、无意义甚至最有可能是编程错误的事情。


那作业

$hash{"snake"}{ACB2}   = (70, 120);

只会分配 value 120,因为分配需要一个标量,但左边有一堆值。

要分配一个数组引用,您必须明确声明它:

$hash{"snake"}{ACB2}   = [70, 120];

您对印记 ( $, @, %) 的使用似乎不合适。

  • 如果$要处理标量或单个数组或哈希值,请使用。
  • 如果@要处理数组(或数组或散列切片(多个值);例如@array[0,2]将返回数组中的第一项和第三项@array),请使用。
  • %如果要处理哈希,请使用。

所以

@sortedarray[-1]

应该

$sortedarray[-1]

因为您只访问一个值。

于 2019-11-22T02:53:19.247 回答
1

如果我对您的理解正确,那么以下代码应该可以满足您的期望。我将结果保存在哈希中,随时以您想要的任何形式打印数据

use strict;
use warnings;

use Data::Dumper;

my $debug = 1;

my %data;
my $totalProteinsSearch = 100;

while( <DATA> ) {
    chomp;
    my @row = split ',';

    $data{$row[0]}{$row[1]} = { proteinLength => $row[2], totalProteins => $row[3] };
}

print Dumper(\%data) if $debug == 1;

my %result;

while( my($organism,$value) = each %data ) {
    while( my($proteinID, $data) = each %{$value} ) {
        next if $data->{totalProteins} < $totalProteinsSearch;
        $result{$organism} = {
                                proteinID => $proteinID,
                                proteinLength => $data->{proteinLength}, 
                                totalProteins => $data->{totalProteins} 
                            }
            if not defined $result{$organism}
                or 
            $data->{proteinLength} > $result{$organism}{proteinLength};
    }
}

print Dumper(\%result) if $debug;

__DATA__
snake,ACB2,70,120
snake,SGJK,183,120
snake,KDMFS,1213,120
snake,VCS2,21,120
bear,ACB2,12,87
bear,GASF,131,87
bear,SDVS,53,87
monkey,ACB2,70,230
monkey,GMSD,234,230
monkey,GJAS,521,230
monkey,ASDA,134,230
monkey,ASMD,700,230

您可以打印信息,例如如下 [关闭调试$debug = 0]

while( my($organism,$data) = each %result ) {
    printf "%s\nLargetst protein: %s [%d]\n\n",
            $organism, 
            $data->{proteinID},
            $data->{proteinLength};
}
于 2019-11-22T04:21:05.743 回答