Reputation: 83
I'm trying to use a foreach
loop to loop through an array and then use a nested while
loop to loop through each line of a text file to see if the array element matches a line of text; if so then I push data from that line into a new array to perform calculations.
The outer foreach
loop appears to be working correctly (based on printed results with each array element) but the inner while loop is not looping (same data pushed into array each time).
Any advice?
The code is below
#! /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
 Standard deviation: $stdev_round Coefficient 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;
}
Upvotes: 0
Views: 2852
Reputation: 53478
Yes, my advice would be:
strict
and warnings
.open ( my $inputfile, "<", 'final_expression.txt' );
die
if it doesn't open - the rest of your program is irrelevant. chomp $line
foreach
loop so your while
loops becomes a null operation. Simplistically, reading the file into an array my @lines = <FILE>;
would fix this.So with that in mind:
#!/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
 Standard deviation: $stdev_round Coefficient 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;
}
Upvotes: 1
Reputation: 56688
The problem here is that starting from the second iteration of foreach you are trying to read from already read file handle. You need to rewind to the beginning to read it again:
foreach $regex (@regex) {
seek FILE, 0, 0;
while ( my $line = <FILE> ) {
However that does not look very performant. Why read file several times at all, when you can read it once before the foreach starts, and then iterate through the list:
my @lines;
while (<FILE>) {
push (@lines, $_);
}
foreach $regex (@regex) {
foreach $line (@lines) {
Having the latter, you might also what to consider using grep
instead of the while
loop.
Upvotes: 0