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

I have a text file which contains

Name subj1 subj2 subj3 Evans 24 45 55 charles 25 24 26
use strict; use warnings; my $line = "test_scores.txt"; open(FH, $line) or die "Cannot open $line"; readline(FH); #<-- read the first line effectively skipping it while($line=<FH>){ if ($line=~m/^C/) { print($line); } }
output: Charles average is:sumofmarks/3

Replies are listed 'Best First'.
Re: Retrieve average
by hippo (Archbishop) on Feb 12, 2019 at 14:30 UTC

    Assuming the leading whitespace is a typo and you are extracting the line correctly, all you need to do is compute and print the average. There are many ways to do this - here is just one:

    #!/usr/bin/env perl use strict; use warnings; use Statistics::Lite 'mean'; my $line = 'Charles 25 24 26'; my ($name, @fields) = split (/ /, $line); my $mean = mean (@fields); printf "%s average is %.2f\n", $name, $mean;
Re: Retrieve average
by haukex (Archbishop) on Feb 12, 2019 at 14:37 UTC

    Hello and welcome to Perl and the Monastery, Tigor!

    Here are my suggestions on how to solve your problem:

    • The problem with the code you showed is that m/^C/ requires an uppercase C at the beginning of the line, but the test data you've showed includes whitespace at the beginning of the line and the name starts with a lowercase c. You can either change the regular expression into m/^\s*C/i to allow for case-insensitive matching and whitespace at the beginning of the line, or you could also remove whitespace from the beginning of the line with $line=~s/^\s+//;. Yet another alternative is to match the name after the split that I describe below, because that will remove the whitespace for you, and then only compare the name itself.
    • You can use split to split the line on whitespace and store it into an array. For example, my @fields = split ' ', $line;
    • You can then use shift to remove the first field from an array. For example, my $first = shift @array;.
    • You can use sum from List::Util to sum a list of numbers. For example, put use List::Util qw/sum/; at the top of your script, and then use my $sum = sum(@array);

    I hope this is enough information to get you started. For a good introduction to Perl in general, see perlintro.

    In addition, here are some stylistic tips:

    • I'd suggest using a separate variable for the filename. For example, my $file = "test_scores.txt";, and later on you can declare $line in the loop with while( my $line=<FH> ).
    • The more modern three-argument open and lexical filehandles are generally recommended. For example, open my $fh, '<', $file or die "$file: $!"; - then, use $fh instead of FH.
Re: Retrieve average
by 1nickt (Canon) on Feb 12, 2019 at 15:24 UTC

    Hi, welcome to Perl, the One True Religion. Read perlintro before you do anything else. Then, learn to use some tools.

    use strict; use warnings; use feature 'say'; use Path::Tiny 'path'; use Text::CSV_XS 'csv'; use Scalar::Util 'looks_like_number'; use List::Util 'sum'; my $filename = path($0)->basename('.pl') . '.txt'; # print the sample data to a file for the purposes of this test path($filename)->spew(do{local $/; <DATA>}); # read in the structured data my $rows = csv( in => $filename, sep_char => " "); # calculate and print the desired results for ( @{ $rows } ) { my @row = @{$_}; next unless looks_like_number($row[1]); # skip headers next unless $row[0] =~ /^C/i; # skip unless name begins +with c/C my $avg = sprintf '%.2f', sum( @row[1 .. $#row] ) / $#row; say sprintf '%s avg: %s', $row[0], $avg; } __DATA__ Name subj1 subj2 subj3 Evans 24 45 55 charles 25 24 26 Carlos 42 0 84

    Hope this helps!


    The way forward always starts with a minimal test.
Re: Retrieve average
by Laurent_R (Canon) on Feb 12, 2019 at 20:17 UTC
    $ perl -wE 'my $str = "Charles 25 24 26"; my ($name, @vals) = split /\ +s+/, $str; $sum += $_ for @vals; say $sum / @vals;' 25
    Or possibly better:
    $ perl -wE 'my $str = "Charles 25 24 26"; my ($name, @vals) = split / +\s+/, $str; my $sum = 0; $sum += $_ for @vals; say $sum / @vals;' 25