在Perl中的foreach循环内运行嵌套的while循环

时间:2015-03-28 19:46:17

标签: perl loops

我正在尝试使用foreach循环遍历数组,然后使用嵌套的while循环遍历文本文件的每一行,以查看数组元素是否与一行匹配文本;如果是这样,那么我将该行中的数据推送到一个新数组中以执行计算。

外部foreach循环似乎正常工作(基于每个数组元素的打印结果),但内部while循环不循环(每次都将相同的数据推入数组)。

有什么建议吗?

代码在

之下
#! /usr/bin/perl -T

use CGI qw(:cgi-lib :standard);

print "Content-type: text/html\n\n";

my $input       = param('sequence');
my $meanexpfile = "final_expression_complete.txt";

open(FILE, $meanexpfile) or print "unable to open file";

my @meanmatches;

@regex = (split /\s/, $input);

foreach $regex (@regex) {

    while (my $line = <FILE>) {
        if ( $line =~ m/$regex\s(.+\n)/i ) {
            push(@meanmatches, $1);
        }
    }

    my $average                  = average(@meanmatches);
    my $std_dev                  = std_dev($average, @meanmatches);
    my $average_round            = sprintf("%0.4f", $average);
    my $stdev_round              = sprintf("%0.4f", $std_dev);
    my $coefficient_of_variation = $stdev_round / $average_round;
    my $cv_round                 = sprintf("%0.4f", $coefficient_of_variation);

    print font(
        { color => "blue" }, "<br><B>$regex average: $average_round   
&nbspStandard deviation: $stdev_round&nbspCoefficient of 
variation(Cv): $cv_round</B>"
    );
}

sub average {
    my (@values) = @_;
    my $count    = scalar @values;
    my $total    = 0;

    $total += $_ for @values;

    return $count ? $total / $count : 0;
}

sub std_dev {
    my ($average, @values) = @_;
    my $count       = scalar @values;
    my $std_dev_sum = 0;

    $std_dev_sum += ($_ - $average)**2 for @values;

    return $count ? sqrt($std_dev_sum / $count) : 0;
}

2 个答案:

答案 0 :(得分:1)

是的,我的建议是:

  • 开启strictwarnings
  • 了解您的代码,
  • 使用3参数open:open ( my $inputfile, "<", 'final_expression.txt' );
  • die如果它没有打开 - 你的程序的其余部分是无关紧要的。
  • chomp $line
  • 你正在迭代你的文件句柄,但是一旦你完成了这个操作,你就会在文件的末尾进行foreach循环的下一次迭代,这样你的while循环就变成了null操作。简单地说,将文件读入数组my @lines = <FILE>;可以解决这个问题。

考虑到这一点:

#!/usr/bin/perl -T

use strict;
use warnings;

use CGI qw(:cgi-lib :standard);
print "Content-type: text/html\n\n";

my $input       = param('sequence');
my $meanexpfile = "final_expression_complete.txt";
open( my $input_file, "<", $meanexpfile ) or die "unable to open file";
my @meanmatches;

my @regex = ( split /\s/, $input );
my @lines = <$input_file>;
chomp (@lines);
close($input_file) or warn $!;

foreach my $regex (@regex) {
    foreach my $line (@lines) {
        if ( $line =~ m/$regex\s(.+\n)/i ) {
            push( @meanmatches, $1 );
        }
    }

    my $average                  = average(@meanmatches);
    my $std_dev                  = std_dev( $average, @meanmatches );
    my $average_round            = sprintf( "%0.4f", $average );
    my $stdev_round              = sprintf( "%0.4f", $std_dev );
    my $coefficient_of_variation = $stdev_round / $average_round;
    my $cv_round = sprintf( "%0.4f", $coefficient_of_variation );

    print font(
        { color => "blue" }, "<br><B>$regex average: $average_round   
&nbspStandard deviation: $stdev_round&nbspCoefficient of 
variation(Cv): $cv_round</B>"
    );
}

sub average {
    my (@values) = @_;
    my $count    = scalar @values;
    my $total    = 0;
    $total += $_ for @values;

    return $count ? $total / $count : 0;
}

sub std_dev {
    my ( $average, @values ) = @_;

    my $count       = scalar @values;
    my $std_dev_sum = 0;
    $std_dev_sum += ( $_ - $average )**2 for @values;

    return $count ? sqrt( $std_dev_sum / $count ) : 0;
}

答案 1 :(得分:0)

这里的问题是从foreach的第二次迭代开始,你试图从已经读过的文件句柄中读取。你需要回到开头再读一遍:

foreach $regex (@regex) {
    seek FILE, 0, 0;
    while ( my $line = <FILE> ) {

然而,这看起来并不高效。为什么要读取文件几次,当你在foreach开始之前读取它一次,然后遍历列表:

my @lines;
while (<FILE>) {
    push (@lines, $_);
}

foreach $regex (@regex) {
    foreach $line (@lines) {

使用后者,您可能还需要考虑使用grep而不是while循环。