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
        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.
        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