我正在解析psiblast的输出报告。我使用COG比对并在基因数据库中搜索匹配(同源物)。我想做的一件事是找出哪些基因与多个COG相匹配。我的部分脚本如下。
我特别难以创建一个数组,该数组包含分配给多个COG的基因的所有COG。
我收到以下错误"不能使用字符串(" COG0003")作为ARRAY ref,而#34; strict refs"在parse_POG_reports.pl第26行第67行使用。"。
我已经查看了其他有关将元素推入数组哈希的帖子。但我认为当一个基因与同一个COG有2个匹配时,可能会发生错误,并且它试图将相同的COG推入数组(即样本输入的最后2行)。这有意义吗?如果是这样,我该如何避免这个问题?
use strict;
use warnings;
my %maxBits;my %COGhit_count;
my $Hohits={};my %COGhits;
my $COG_psi_report=$ARGV[0];
open (IN, $COG_psi_report) or die "cannot open $COG_psi_report\n";
while (my $line=<IN>){
next if ($line =~/^#/);
chomp $line;
my @columns = split(/\t/,$line);
my $bits=$columns[11];
my $COG=$columns[0];
my $hit=$columns[1];
my $Eval=$columns[10];
next if ($Eval > 0.00001); # threshold for significant hits set by DK
$COGhit_count{$hit}++; # count how many COGs each gene is homologous to
$COGhits{$hit}=$COG;
if ($COGhit_count{$hit}>1) {
push @{$COGhits{$hit}}, $COG; #
}
## for those that there are multiple hits we need to select top hit ##
if (!exists $maxBits{$hit}){
$maxBits{$hit}=$bits;
}
elsif (exists $maxBits{$hit} && $bits > $maxBits{$hit}){
$maxBits{$hit}=$bits;
}
$Hohits->{$hit}->{$bits}=$COG;
}
close (IN);
示例输入:
POG0002 764184357-stool1_revised_scaffold22981_1_gene47608 23.90 159 112 3 1 156 1 153 2e-06 54.2
POG0002 764062976-stool2_revised_C999233_1_gene54902 23.63 182 121 5 3 169 2 180 2e-06 53.9
POG0002 763901136-stool1_revised_scaffold39447_1_gene145241 26.45 155 89 3 3 137 5 154 3e-06 53.9
POG0002 765701615-stool1_revised_C1349270_1_gene168522 23.53 187 115 5 3 169 2 180 5e-06 53.1
POG0002 158802708-stool2_revised_C1077267_1_gene26470 22.69 216 158 5 3 213 5 216 5e-06 52.7
POG0003 160502038-stool1_revised_scaffold47906_2_gene161164 33.00 297 154 6 169 424 334 626 6e-40 157
POG0003 160502038-stool1_revised_scaffold47906_2_gene161164 16.28 172 128 4 23 192 46 203 1e-06 56.6
POG0003 158337416-stool1_revised_C1254444_1_gene13533 30.06 346 184 7 133 424 57 398 6e-40 155
POG0003 158337416-stool1_revised_scaffold29713_1_gene153054 28.61 332 194 8 132 424 272 599 2e-38 152
POG0003 158337416-stool1_revised_scaffold29713_1_gene153054 24.00 200 131 5 1 193 5 190 9e-11 69.3
答案 0 :(得分:1)
你需要摆脱第24行(倒数):
$COGhits{$hit}=$COG;
其中,您将$COGhits{$hit}
设置为标量值($COG
的值)。稍后,在第26行中,您尝试取消引用$COGhits{$hit}
作为一个数组来推入它。这不起作用,因为那里有一个标量。
只需删除if
并将这些行更改为此行。这应该可以解决问题,因为现在所有$hit
都存储在数组引用中。
$COGhit_count{$hit}++; # count how many COGs each gene is homologous to
push @{$COGhits{$hit}}, $COG;
$COGhits
的输出:
$VAR4 = {
'158802708-stool2_revised_C1077267_1_gene26470' => [
'POG0002'
],
'764062976-stool2_revised_C999233_1_gene54902' => [
'POG0002'
],
'764184357-stool1_revised_scaffold22981_1_gene47608' => [
'POG0002'
],
'765701615-stool1_revised_C1349270_1_gene168522' => [
'POG0002'
],
'763901136-stool1_revised_scaffold39447_1_gene145241' => [
'POG0002'
],
'160502038-stool1_revised_scaffold47906_2_gene161164' => [
'POG0003',
'POG0003'
]
};
如果你想要标量和数组引用,请尝试使用此代码。 我不推荐这个。
$COGhit_count{$hit}++; # count how many COGs each gene is homologous to
if ($COGhit_count{$hit} == 1) {
$COGhits{$hit}=$COG; # Save as scalar
}
elsif ($COGhit_count{$hit} == 2) { # If we've just found the second hit,
my $temp = $COGhits{$hit}; # save the first and convert $COGhits{$hit}
$COGhits{$hit} = []; # to an array ref, then push both the old and
push @{$COGhits{$hit}}, $temp, $COG; # the new value in it.
} elsif ($COGhit_count{$hit} > 2) {
push @{$COGhits{$hit}}, $COG; # Just push the new value in
}
思考:你可能先$COGhits{$hit}=$COG
但后来注意到有时会有多个值,所以你添加了push
行,但你没有意识到你实际上必须更换旧线。
答案 1 :(得分:0)
它告诉你完全你做错了什么。
$COGhits{$hit}=$COG; # <--- scalar
if ($COGhit_count{$hit}>1) {
push @{$COGhits{$hit}}, $COG; # <--- array
}
您不能将该值指定为非引用类型,然后尝试将其自动生成为引用类型。 Perl将执行后者,但如果您已经在该位置存储了冲突的数据类型,则不会。
另外,如果这个奇迹出现在第一次(它赢了),并且你不止一次地运行它,那么你可能通过推送自动生成的任何数组都会受到标量的破坏。非参考作业。
我不确定你之后会发生什么,但第一行可能会被删除。
您想要确定$COG
的值$hit
是否会有多个规范,而不是该构造。如果可以,只需用push
替换这4行即可。
之前我已经完成了多功能结构插槽,它们很难维护。但如果你想做类似的事情,你可以这样做:
my $ref = \$hashref->{ $key }; # autovivifies slot as simple scalar.
# it starts out as undefined.
if ( ref $$ref ) { # ref $ref will always be true
push @$$ref, $value;
}
else {
$$ref = defined( $$ref ) ? [ $$ref, $value ] : $value;
}
但是每次要以某种不同的方式访问混合树时,都必须编写分叉逻辑。通过测试和分支,您可以节省使用标量所带来的性能节省。
所以我不再做太多了。我事先决定关系是1-1还是1-n。在某种程度上,像下面这样的例程可以使它更直接地处理这些类型的表。
sub get_list_from_hash {
my ( $hash, $key ) = @_;
my $ref = \$hash->{ $key };
return unless defined( $$ref );
return ref( $$ref ) ? @$$ref : $$ref;
}
sub store_in_hash {
$_[0] = {} unless ref $_[0];
my ( $hash, $key, @values ) = @_;
my @defined = grep {; defined } @values;
unless ( @defined ) {
delete $hash->{ $key };
return;
}
my $ref = \$hash->{ $key };
if ( ref $$ref ) {
push @$$ref, @defined;
}
elsif ( defined $$ref ) {
$$ref = [ $$ref, @defined ];
}
elsif ( @values > 1 ) {
@$$ref = @defined;
}
else {
( $$ref ) = @defined;
}
}