第一次在这里发帖,希望有人可以帮助我。我是编程和perl的新人,目前正在大学修读课程。
我的问题是关于以下子程序,它将数组和标量(字符串)作为参数。我通过引用数组调用子例程,并在子例程中取消引用。
作为参数传递给子程序的引用数组的长度不为0.在子程序中取消引用后得到的数组长度为0.我不明白为什么。
sub calc_average {
my @indexes = @{$_[1]};
print @indexes."\n"; #test only
my $line = $_[0];
#my $sum = 0;
#my @row=split(/\t/,$line);
#for (my $i=0; $i<@indexes; $i++){
# my $sum = $sum + $row[$indexes[$i]];
#}
#my $average = $sum/scalar(@indexes);
#print $average."\n"; #test only
#return $average;
}
这打印0.子程序用:
调用calc_average($line, \@GC_indexes)."\n";
@GC_indexes
不是空的。 $line
是文件中的一行文字。
提前致谢!
答案 0 :(得分:4)
my $sum = $sum + $row[$indexes[$i]];
不应在循环中使用my
声明。
您正在为$sum
循环的每次迭代创建一个新的for
(在for
循环的范围内)。当循环结束时,在那里创建的$sum
超出范围,程序使用您在循环之前创建的$sum
(等于0)。
答案 1 :(得分:1)
您可以将数组传递给子函数的另一种方法如下
calc_average($line,\@GC_indexes);
sub calc_average{
my ($line,$index) = @_;
my @indexes = @{$index};
print scalar(@indexes); #should print the length of your array
}
你可以填写剩下的部分,我以为我会分享。
答案 2 :(得分:0)
而不是你得到的解决方案,它对我来说很好评论。您的问题应该包含一个可验证的示例。请阅读How to create a Minimal, Complete, and Verifiable example
评论你所知道的代码不起作用将无法帮助你找到解决方案:它让我们无需工作。在这种情况下,我所要做的就是删除你的评论
这是您的问题的MCVE
use strict;
use warnings 'all';
use Data::Dump;
my $line = join "\t", 1 .. 100;
my @GC_indexes = (7, 14, 42);
print calc_average($line, \@GC_indexes), "\n";
sub calc_average {
my @indexes = @{$_[1]};
print @indexes."\n"; #test only
my $line = $_[0];
my $sum = 0;
my @row=split(/\t/,$line);
for (my $i=0; $i<@indexes; $i++){
my $sum = $sum + $row[$indexes[$i]];
}
my $average = $sum/scalar(@indexes);
print $average."\n"; #test only
return $average;
}
3
0
0
正如您所知,主要问题是您在$sum
循环中声明了 new for
。每次循环时,内部$sum
被声明并以值undef
开始,然后它增加$row[$indexes[$i]]
并在循环块结束时被丢弃。您打算使用之前声明过几行的外部 $sum
请注意以下几点
您必须始终使用use strict
和use warnings 'all'
启动每个Perl程序。这将极大地帮助您可能会忽略大量的微不足道的错误,并且在您向其他人寻求帮助之前应该采取适当的措施
使用更多的空格可以清楚地了解程序的基本单位的开始和停止位置。例如,操作符应该与它们的操作数分开,并且块应该与其周围的代码明显区分
标量上下文中的数组计算数组中元素的数量;当插入到字符串中时,它们形成一个由内置变量$"
的内容分隔的字符串,通常作为单个空格,在列表上下文中(如子程序调用的参数中),它们被评估为列表他们的元素
这意味着print @indexes."\n"
将打印@indexes
中的元素数量,后跟换行符,而print "@indexes\n"
将打印@indexes
的内容使用换行符,print @indexes, "\n"
将打印数组的所有元素(没有分隔符)和换行符
我不确定你的意思
很少需要C风格的for
循环。通常你只需要迭代一个列表。所以for (my $i=0; $i<@indexes; $i++)
几乎肯定会更好for my $i ( 0 .. $#indexes )
你几乎不需要$i++
。该表单已经被C ++语言的名称所推广,但是递增$i
也有在递增之前返回值的负担。大多数现代语言都会优化它,但你不应该依赖它,它也打破了将动词放在名词之前的规则
表达式$#array
的计算结果为@array
的最后一个索引。它被设计用于像这样的实例
表达式$sum/scalar(@indexes)
不需要scalar
运算符。如前所述,标量上下文中的@array
(由/
运算符提供)评估@array
中元素的数量,因此您只需要$sum/@indexes
我写过这个解决方案。你自己的子程序(删除了注释)是calc_average0
,而我写的是calc_average1
。正如我所描述的那样,你自己的子程序打印引用传递的数组@GC_indexes
中的元素数,然后是零,因为外部$sum
永远不会从其初始化改变
我希望这会有所帮助
use strict;
use warnings 'all';
use Data::Dump;
my $line = join "\t", 1 .. 100;
my @GC_indexes = ( 7, 14, 42 );
calc_average0( $line, \@GC_indexes );
calc_average1( $line, \@GC_indexes );
sub calc_average0 {
my @indexes = @{ $_[1] };
print @indexes . "\n"; #test only
my $line = $_[0];
my $sum = 0;
my @row = split( /\t/, $line );
for ( my $i = 0; $i < @indexes; $i++ ) {
my $sum = $sum + $row[ $indexes[$i] ];
}
my $average = $sum / scalar(@indexes);
print $average. "\n"; #test only
return $average;
}
sub calc_average1 {
my ( $line, $indexes ) = @_;
my @line = split /\t/, $line;
my $sum = 0;
$sum += $line[ $indexes->[$_] ] for 0 .. $#{$indexes};
my $average = $sum / @$indexes;
print "calc_average1: $average\n"; #test only
return $average;
}
3
0
calc_average1: 22