joachim has asked for the wisdom of the Perl Monks concerning the following question:

Hi.... I am new to perl.... and after reading up on how to write scripts. I find I am not able to do this simple thing. I can do it in Excel but I would like a script in perl to do the same thing. Here's the details I have a file....... date:col1:col2:col3 20010102:21:45:25 20010103:14:20:15 etc......... 20010124:10:8:10 What I would like to do is find the 10 day average of col3 and the 5 day average of col2...... and write all of this to a log file......like this... "Name of file" average col2 value of last entry col2 average col3 value of last entry of col3 ( last entry is the last line in the file ie 20010124.. Could someone please have a look at this and help me out here...??? Thank you Joachim

Replies are listed 'Best First'.
Re: Basic math with data
by lemming (Priest) on Jan 25, 2001 at 06:23 UTC
    This sounds a lot like homework:
    In any case the functions you'll be wanting to use are open and split. Though open can be skipped if you just want to use @ARGV as your file argument. Error checking is another consideration and will get you better grades.
      It does sound like homework, but joachim's been around for a bit and I've never heard him come up with a homework question before. Still, I think you've found the balance between helpful hinting and harmful hinting.

      Update: I looked at joachim's home node and saw that he first logged in yesterday. My memory was faulty--I stand corrected.

      Nope.... not homework. However I am flattered. This is a project for myself. It was something triggered my a conversation with one of my friends .... who said it couldn't be done. I see how quickly you monks have cobbled up text messages rather than just pluck down script. I must surmise that it's not that easy. Perhaps we should begin..... I have all night. #!/usr/bin/perl -w use strict; my $infile = shift; my $outfile = shift; open (IN, $infile) || die "can't open $infile: $!"; open (OUT, ">$outfile")|| die "can't open $outfile: $!"; while (<IN>) { chomp; my @fields = split /,/; #let's see what you can place here to make it work...... #Sorry about the mess.... but it looks better when I typed #out the thing in the first place. #BTW..... If this can't be done... to bad .... I'll just have #to go back to the book and maybe in year or two.... I'll be #able to write the script myself..... I'd rather not wait #that long..... thanks # Joachim close (IN); close (OUT); __END__
Re: BASIC MATH WITH DATA
by chipmunk (Parson) on Jan 25, 2001 at 19:43 UTC
    Here's one way to find the most recent 10 day average for column 3:
    #!perl -w use strict; my @lines; while (<>) { push @lines, $_; shift @lines if @lines > 10; } chomp(@lines); my @cols; my $total = 0; for (@lines) { @cols = split /:/; $total += $cols[3]; } my $average = $total / (@lines || 1); # if no lines, avoid division by zero print "Average of column 3 for the last ", scalar(@lines), " days: $average\n";
    I hope that gets you started!

    Update: Have to specify $_ in the call to push. Bad chipmunk! No acorns!

      Just a little more Help here..... and I think it will work. I added some stuff to make the script load a file and output a log file. However there is some error in the script that I cannot resolve. Could someone please have a look....?? while we are editing the $text line..... could you also include the value of the most resent value entered in col3
      #!/usr/bin/perl -w $infile = shift; $outfile = shift; open(IN, $infile) || die("Can't open input file $infile - $!"); open(OUT, ">$outfile") || die("Can't open output file $outfile +- $!"); use strict; my $text; my @lines; while (<>) { push @lines; shift @lines if @lines > 10; } chomp(@lines); my @cols; my $total = 0; for (@lines) { @cols = split /:/; $total += $cols[3]; } my $average = $total / (@lines || 1); # if no lines, avoid division by zero ***** error here***** $text= "Average of column 3 for the last " + ;#, scalar(@lines)," days: $average\n"; print OUT "$text\n"; close IN; close OUT ;
      So the message in the Data.log file would read "<Filename> Average is <average> the last was <most resent entry for col3>" Thank you.. this has been good experience..... wish something like this was in the book I bought. joachim
        You might want to read from your IN file.
        Try <IN> instead of just <>.

        Editorial: Instead of just cut and pasting chipmunk's code, try to understand what it does. Pick up Learning Perl, browse the other book reviews & purchase other worthy recommended books

        Quote:
        $text= "Average of column 3 for the last " ; #, scalar (@lines)," days: $average\n";
        Originally, that was a print statement, in which the commas were fine. With a scalar assignment, the commas should be replaced with concatenation:
        $text = "Average of column 3 for the last " . scalar(@lines) . " days: $average\n";
        or with join:
        $text = join '', "Average of column 3 for the last ", scalar(@lines), " days: $average\n";
        or with a single interpolated string, or with sprintf... There's more than one way to do it.
         

        The last line is at @lines[-1]; one way to get the most recent value is: my $last = (split /:/, $lines[-1])[3]; The ( )[3] is called a list slice. It's basically a short way of doing:

        my @tmp = split /:/, $lines[-1]; my $last = $tmp[3];
        Instead of assigning to the array @tmp and then looking up index 3, the list slice just does the index directly on the list. They give the same results, though, so use whichever is clearer.