KGee
KGee

Reputation: 373

How to print the last value of my output in perl?

I wrote a script which, for the first time, works as I want :P I will provide my script below. The only thing that I wish to do, and I didn't succeed, was to print ONLY the last value of my output.

use strict;
use warnings;
use feature 'say';

my $filename = '/home/Desktop/my_scripts/coordinates_based';

my $p;
my $i;
my $mikos = 0;
my $sum = 0;
my $count = 1;
my $mikos_thetika = 0;
my $mikos_arnitika = 0;
my $k = 1;
my @table = ();
my $final = 0;
my $neg = 0;
my $pos = 0;
my $size;
my $last_value = 0;

open(FH, '<', $filename) or die $!;

while (<FH>) {

    my ($n, $p, $a, $b) = split '\s+';

    chomp;
    $i =  1 if $p eq '+';
    $i = -1 if $p eq '-';

    for ($k..$n)
    {
        $mikos = $b - $a;
        if ($p eq '+')
        {
            $mikos_thetika = $mikos*1 ;
            $pos += $mikos_thetika;
        }
        else
        {
            $mikos_arnitika = $mikos*(-1);
            $neg += $mikos_arnitika;
        }

        $final = $pos + $neg;

        #chomp;
        #push(@table, $final);

        #$size = scalar @table;
        say $final;

        $k = $k + 1;
    }
}
close(FH);

Script explanation : the output calculates the difference between $b and $a and based on $p print its difference with the - or + respectively. And at the end prints the sum of those difference but not in total as I want but as a sum ($final) of previous value with the coming one.

I tried these:

1)  if ($k==$n) # $n is first column of my input file
    {$last_value =$table[$k];}
    say $last_value; # But it prints the same output.

2)  $size= scalar @table;
    $last_value = $table [$size];
    say $size; # prints the correct table size but not as value 
               # but as an entire sequence. For example 
               # if my table size is 5 it prints 1\n 2\n 3\n 4\n 5

3) # Also i tried the List library 
    use List::Util qw(sum);
    $last_value=sum($final);

input file :

$n $p $a $b   
1 - 852 1934
2 - 2020 3108
3 + 3212 3781
4 - 3917 4162
5 - 4263 4421

output file after my script

-1082
-2170
-1601
-1846
-2004

Desired output

2004

Upvotes: 1

Views: 551

Answers (2)

Polar Bear
Polar Bear

Reputation: 6798

Well, I took some liberty to clean up your code.

Please see if you find the following code snippet easier to read/understand than your original.

It serves same purpose/function as your original code, except per your request output final result after all data processed right before program exits.

Note: zdim brought to my attention that code can be improved with split special case, if ... else ... CPU cycle efficiency (for sanitized input data) and regarding header skip code (header can be absent or have different format). Although initially I did not intended to make improvement of the code but only code readability, I consider zdim's suggestion a worthwhile change.

Note: input data sanitized with next unless /\d+ +[+-] +\d+ +\d+/; what might look somewhat unusual as normally it is written as next unless /\d+\s+[+-]\s+\d+\s+\d+/; -- it is more for demonstration purpose that same goal can be achieved in different ways. I assumed potential cases inconsistency of input data when data fields can be separated with more than one space (user could adjust spacing for readability). ' ' and \s is quite different as first assumes only ' ' (space) but '\s' assumes [ \f\n\r\t]. perlre

use strict;
use warnings;
use feature 'say';

my $filename = 'coordinates_based';    # I run code in same directory as input file

my($k,$pos,$neg,$final);               # only necessary variables for computation 

$k = 1;
$pos = $neg = 0;                       # some variables initialization

open my $fh, '<', $filename
    or die "Could not open $filename: $!";

while (<$fh>) {                             # walk through file
    next unless /\d+ +[+-] +\d+ +\d+/;      # sanitize input data
    chomp;

    my ($n, $p, $a, $b) = split;            # see split doc for special case

    for ($k..$n)
    {
        if ($p eq '+') {
            $pos += $b-$a;   # thetika  (positive)
        } else {
            $neg -= $b-$a;   # arnitika (negative)
        }

        $final = $pos + $neg;

        $k++;
    }
}

close $fh;

say $final;                            # output result of computation

Output

-2004

Upvotes: 2

brian d foy
brian d foy

Reputation: 132792

You basically have this situation, where at the end of each iteration you output something. You keep doing this because you don't know when you'll get to the last element.

while( <FH> ) {
    say $_ ** 2;
    }

Instead of outputting something, save the result for output later. When you run into another element, replace that value. When you run out of input, the last value that you remembered is the value that you want to output:

my $previous_output;
while( <FH> ) {
    $previous_output = $i ** 2;
    }

say $previous_output;

Or, you can cheat by making all of the output and grabbing just the last line with tail (or something similar):

% perl script.pl | tail -n 1

Upvotes: 5

Related Questions