On Feb 13, 2013, at 6:47 PM, Tiago Hori wrote:

> Hey Guys,
> 
> I am still at the same place. I am writing these little pieces of code to
> try to learn the language better, so any advice would be useful. I am again
> parsing through tab delimited files and now trying to find fish from on id
> (in these case families AS5 and AS9), retrieve the weights and average
> them. When I started I did it for one family and it worked (instead of the
> @families I had a scalar $family set to AS5). But really it is more useful
> to look at more than one family at time (I should mention that are 2 types
> of fish per family one ends in PS , the other doesn't). So I tried to use a
> foreach loop to go through the file twice, once with a the search value set
> to AS5 and a second time to AS9. It works for AS5, but for some reason, the
> foreach loop sets $test to AS9 the second time, but it doesn't go through
> the while loop. What am I doing wrong?
> 
> here is the code:
> 
> #! /usr/bin/perl
> use strict;
> use warnings;
> 
> my $file = $ARGV[0];
> my @family = ('AS5','AS9');
> my $i;
> my $ii;
> my $test;
> 
> open (my $fh, "<", $file) or die ("Can't open $file: $!");
> 
> foreach (@family){
>    $test = $_;

You can combine those two lines like this (for and foreach are equivalent, so 
most people use the shorter form):

  for my $test ( @family ) {

>    my @data_weight_2N = ();
>    my @data_weight_3N = ();

The second time through the for loop, the file has been read and is positioned 
at its end. You are going to get nothing by reading the file the second time 
through. You should rewind the file:

  seek($fh,0,0);

>    while (<$fh>){
>        chomp;
>        my $line = $_;

Once again, you can do the assignment directly and not use the default variable 
$_. It is shorter and better:

  while( my $line = <$fh> ) {
    chomp($line);

>        my @data  = split ("\t", $line);
>        if ($data[0] !~ /[0-9]*/){
>        next;}

Better syntax for those two lines:

  next if $data[0] !~ /[0-9]*/;

>        elsif ($data[1] eq "ABF09-$test"){

Then you can make the above line 'if …'

>            $i += 1;
>            push (@data_weight_2N,  $data[6]);
>        }elsif ($data[1] eq "ABF09-".$test."PS"){
>        $ii += 1;
>            push (@data_weight_3N,$data[6]);
>    }
> }
>    my $mean_2N = &average (\@data_weight_2N);
>    my $stdev_2N = &stdev (\@data_weight_2N);

You should not be calling subroutines with the ampersand character.

>    my $stderr_2N = ($stdev_2N/sqrt($i));
> 
>    print "These are the the avearge weight, stdev and stderr for $test
> 2N:\t", $mean_2N,"\t",$stdev_2N,"\t",$stderr_2N, "\n";

It is more efficient to print one double-quoted string than a series of short 
strings,
even if you have to concatenate the string from two shorter strings:

   print "These are the the avearge weight, stdev and stderr for $test" .
    " 2N:\t$mean_2N\t$stdev_2N\t$stderr_2N\n";

> 
>    my $mean_3N = &average (\@data_weight_3N);
>    my $stdev_3N = &stdev (\@data_weight_3N);
>    my $stderr_3N = ($stdev_3N/sqrt($i));
> 
>    print "These are the the avearge weight, stdev and stderr for $test
> 3N:\t", $mean_3N,"\t",$stdev_3N,"\t",$stderr_3N, "\n";
> }
> 
> close ($fh);
> 
> sub average{
>        my($data) = @_;
>        if (not @$data) {
>                print ("Empty array\n");
>                return 0;
>        }
>        my $total = 0;
>        foreach (@$data) {
>                $total += $_;
>        }

Shorter:

  $total += $_ for @$data;

>        my $average = $total / @$data;
>        return $average;
> }
> 
> sub stdev{
>        my($data) = @_;
>        if(@$data == 1){
>                return 0;
>        }
>        my $average = &average($data);
>        my $sqtotal = 0;
>        foreach(@$data) {
>                $sqtotal += ($average-$_) ** 2;
>        }
>        my $std = ($sqtotal / (@$data-1)) ** 0.5;
>        return $std;
> }
> 
> Thanks,


--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to