in reply to Re^18: How to store the output from foreach loop into variable/array without printing?
in thread How to store the output from foreach loop into variable/array without printing?

Can I ask if I could also take a look at how you get the average of the ratio values as well?

Sure, here it is both makeRatioAvg and makeFinal

my $avgRatio = makeRatioAvg ( $ratio_ref ); my $final = makeFinal( $avgRatio ); dd( { avgRatio => $avgRatio }, { final => $final } ); sub makeRatioAvg { print "makeRatioAvg \n"; my( $ratio ) = @_; my $rows = $#$ratio; my $columns = $#{ $ratio->[0] }; my $half_rows = $rows / 2; my $halff = int( 1 + $half_rows ); ## eew my @avg; for my $tre ( 0 .. $columns ) { for my $tri ( 0 .. $columns ) { my $avg = 0; for my $six ( 0 .. $half_rows ) { my $val = $ratio->[$six][$tri][$tre]; $avg += $val; print " + $val "; } $avg = $avg / $halff; print " == $avg \n"; push @avg, $avg; } } for my $tre ( 0 .. $columns ) { for my $tri ( 0 .. $columns ) { my $avg = 0; for my $six ( $halff .. $rows ) { my $val = $ratio->[$six][$tri][$tre]; $avg += $val; print " + $val "; } #~ $avg = $avg / 3; $avg = $avg / $halff; print " == $avg \n"; push @avg, $avg; } } return \@avg; } ## end sub makeRatioAvg sub makeFinal { my( $avgRatio ) = @_; my @first = @{$avgRatio}[ 0 .. ($#$avgRatio/2) ]; my @second = @{$avgRatio}[ (1+($#$avgRatio/2) ) .. $#$avgRatio ]; my @final = map { [ $first[$_] ] , [ $second[$_] ] } 0 .. $#first; return \@final; }

As you might guess, makeRatioAvg and makeFinal is still me following closely the pencil and paper moves -- didn't want to get lost :) Now I have reference program with reference test data, so if I get ambitious and try to combine makeRatioAvg+makeFinal I will notice easily when I make mistake :)


Another question, when splitting the data (by tab since its tab delimited file), it will be split according to columns right (downwards). Is it possible to split by rows (horizontal)? Will that be easier for this kind of ratio thing or it doesn't make a difference?

I'm not quite sure what you mean, but I doubt it makes much of a difference, here is why

rows are lines ... each lines consists of tab seperated values (columns of a row) , so you're already doing what is possible in the most straight forward way

the only issue I saw with your code is you had "while while" loop, where the outer while was used just for the header ... I wrote that as

sub spankTheMonkey { my( $infh ) = @_; my @full_data; my $header = readline $infh; if( $header =~ /\d+/ ) { ## in case there is no header push @full_data, [ split ' ', $header ]; } push @full_data, [split] while( <$infh> ); return \@full_data; } ## end sub spankTheMonkey

It was called from DoWorkOriginal

sub DoWorkOriginal { my( $firstinput, $secondinput, $inFile, $outFile ) = @_; use autodie qw/ open close /; open my $curInfile, '<:raw', $inFile; ## or die by autodie open my $OUT1, '>:raw', $outFile; ## or die by autodie my $full_data = spankTheMonkey( $curInfile ); monkeyBusiness( $firstinput, $secondinput, $OUT1, $full_data ); close $curInfile; close $OUT1; } ## end sub DoWorkOriginal

Where sub monkeyBusiness is the foreach loops from your code which I didn't understand

The general strategy when I don't understand why/how something works, before I can begin to debug/improve, is to isolate/sequester everything into subroutines, and make sure it produces same output as original

  • Comment on Re^19: How to store the output from foreach loop into variable/array without printing?
  • Select or Download Code

Replies are listed 'Best First'.
Re^20: How to store the output from foreach loop into variable/array without printing?
by hellohello1 (Sexton) on Mar 21, 2014 at 08:38 UTC
    Thank you :) I am a very slow learner, so it will take me quite a while for me to digest and reply you.

    Before that, I want to clarify something really noob:

    my( $infh ) = @_;
    @_ refer to the whole dataset right? But if I want to only include data from column 4 onward to the end, I have to write a function to split the data and then take column 4 to end and put it into @_?

      @_ refer to the whole dataset right?

      Do a ctrl+f for spankTheMonkey to see what spankTheMonkey is being given (which args are passed)

      Then see perlvar#@_ Within a subroutine the array @_ contains the parameters passed to that subroutine.

      So, @_ is not "the whole dataset", there is no variable "the whole" of type "dataset" :)

      But if I want to only include data from column 4 onward to the end, I have to write a function to split the data and then take column 4 to end and put it into @_?

      Yes, you can modify spankTheMonkey to discard parts ... essentially turning it from readFullData into readColumnRange( $in_filehandle, 4 .. 10 );

      perlintro#Arrays ought to help

        ok! Thank you for the clarification! I'll get back to reading all these up. :)
        Hi,

        ok. I actually continue using my code as I feel more familiarize with it but did accordingly to how you advise me and I can come out with the output I want:

        while(<CURINFILE>) { push @full_data , [split] while (<CURINFILE>); for $arr_ref1 (@full_data) { for $arr_ref2(@full_data) { $variable1 = ''; $variable2 = ''; for my $index1 (3..4) { $ratio1 = sprintf( "%.4f%s", $$arr_ref2[$index1]/$$arr_ref1 +[$index1],"\t"); $variable1 .= $ratio1; } for my $index2 (5..6) { $ratio2 = sprintf( "%.4f%s", $$arr_ref2[$index2]/$$arr_ref1 +[$index2],"\t"); $variable2 .= $ratio2; } #Calculate Average @arrayint1 = split (/\t/,$variable1); $avg1 = &average (\@arrayint1); #print OUT1 "\t$avg1"; @arrayint2 = split (/\t/,$variable2); $avg2 = &average (\@arrayint2); #print OUT1 "\t$avg2"; #Calculate SD @arrayint1 = split (/\t/,$variable1); $std1 = &stdev(\@arrayint1); #print OUT1 "\t$std1"; @arrayint2 = split (/\t/,$variable2); $std2 = &stdev(\@arrayint2); #print OUT1 "\t$std2"; #Calculate CV $cv1 = $std1/$avg1; $cv2 = $std2/$avg2; my $outputa = "$$arr_ref1[0]"; my $outputb = "$variable1\t$variable2\t"; my $outputc = "\t$avg1\t$avg2"; my $outputd = "\t$cv1\t$cv2"; ###### print everything out ##################### my $key = "$outputa"."$outputb". "$outputc"."outputd"; print OUT1 $key; print OUT1 "\n"; } } sub average{ my($data) = @_; if (not @$data) { die("Empty array\n"); } my $total = 0; foreach (@$data) { $total += $_; } 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; }
        so the output will be :
        _OUTPUT_ M446T27 1 1 1 1 1 1 0 0 M446T27 1.75 2.66 1.80 2.16 2.20 1.98 0.29 0.12 M446T27 1.00 1.64 0.99 1.09 1.32 1.04 0.34 0.06 . .
        So far so good. Phew! Thanks to your guidance! :)

        My next question is, is it possible to actually filter the whole row based on the outputd(set condition)?

        (not sure if it should be put into a new thread?)