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

I started perl a few days ago so are there any ways to make this chunk of code more efficient? The user is supposed to input a score and it'll display something like "The student has gotten a A grade for the score of 100."

#!/usr/bin/perl -w if($ARGV[0] ~~ [0..39]){ print "The student has gotten a F grade for the score of $ARGV[0]. +"; }elsif($ARGV[0] <= 49) { print "The student has gotten a E grade for the score of $ARGV[0]. +"; }elsif($ARGV[0] <= 59) { print "The student has gotten a D grade for the score of $ARGV[0]. +"; }elsif($ARGV[0] <= 64) { print "The student has gotten a C grade for the score of $ARGV[0]. +"; }elsif($ARGV[0] <= 69) { print "The student has gotten a C+ grade for the score of $ARGV[0] +."; }elsif($ARGV[0] <= 74) { print "The student has gotten a B grade for the score of $ARGV[0]. +"; }elsif($ARGV[0] <= 79) { print "The student has gotten a B+ grade for the score of $ARGV[0] +."; }elsif($ARGV[0] <= 100) { print "The student has gotten a A grade for the score of $ARGV[0]. +"; }else { print "Please enter a value between 0 and 100"; }
Thanks in advance. Victor

Replies are listed 'Best First'.
Re: Conditional statement
by moritz (Cardinal) on Apr 24, 2012 at 17:26 UTC

    There's no point in speeding up something that you do only once or twice (though there's still good reason to make it nicer to read).

    If you do many such lookups, just construct an array with the grades and look it up:

    # do this once: my @grades = ( ('F' ) x 40, # 0..39 ('E' ) x 10, # 40..49 ('D' ) x 10, # 50..59 ('C' ) x 5, # 60..64 ('C+') x 5, # 65..69 ... ); # do this many times: my $grade = $grades[$ARGV[0]]; print "The student has gotten a $grade grade for the score of $ARGV[0] +.";

      And in case you did not want to have to count then number of different numbers that get the same grade, you could assign it like this:

      my @grades; @grades[0..39] = ('F') x 50; @grades[40..49] = ('E') x 50; @grades[50..59] = ('D') x 50; @grades[60..64] = ('C') x 50; @grades[65..69] = ('C+') x 50; ...
      You just have to make sure the number at the end of the assignments is higher than the maximum number of scores with the same grade.

      Another option would be this:

      my @grades; $_ = 'F' for @grades[0..39]; $_ = 'E' for @grades[40..49]; $_ = 'D' for @grades[50..59]; $_ = 'C' for @grades[60..64]; $_ = 'C+' for @grades[65..69]; ...

      Jenda
      Enoch was right!
      Enjoy the last years of Rome.

Re: Conditional statement
by toolic (Bishop) on Apr 24, 2012 at 17:31 UTC
    Another way, which looks a little nicer using Switch statements
    use warnings; use strict; use feature "switch"; my $letter; given ($ARGV[0]) { when ([0..39]) { $letter = 'F' ; } when ($_ <= 49) { $letter = 'E' ; } when ($_ <= 59) { $letter = 'D' ; } when ($_ <= 64) { $letter = 'C' ; } when ($_ <= 69) { $letter = 'C+'; } when ($_ <= 74) { $letter = 'B' ; } when ($_ <= 79) { $letter = 'B+'; } when ($_ <= 100) { $letter = 'A' ; } } if ($letter) { print "The student has gotten a $letter grade for the score of $AR +GV[0].\n"; } else { print "Please enter a value between 0 and 100\n"; }

    UDPATE: Here is the original question before the owner deleted it:

      Thanks I appreciate it.
Re: conditional statement
by BillKSmith (Monsignor) on Apr 24, 2012 at 19:38 UTC
    The following version uses the same logic as the original, is easy to understand (and modify), and works on very old versions of perl.
    use strict; use warnings; my ($score) = @ARGV; die "Score must be less than or equal to 100.\n" if $score > 100; my $letter_grade = $score <= 39 ? 'F' : $score <= 49 ? 'E' : $score <= 59 ? 'D' : $score <= 64 ? 'C' : $score <= 69 ? 'C+' : $score <= 74 ? 'B' : $score <= 79 ? 'B+' : 'A' ; print "The student has gotten a $letter_grade for the score of $score\ +n";
Re: conditional statement
by aaron_baugher (Curate) on Apr 25, 2012 at 01:34 UTC

    A subroutine with a series of returns is one way to make the logic simple and clear:

    #!/usr/bin/env perl use Modern::Perl; sub figure_grade { my $n = shift; return undef if $n =~ /\D/ or $n > 100 or $n < 0; return 'A' if $n > 79; # 80% == A? Serious grade inflation! return 'B+' if $n > 74; return 'B' if $n > 69; return 'C+' if $n > 64; return 'C' if $n > 59; return 'D' if $n > 49; return 'E' if $n > 39; return 'F'; } my $g = figure_grade($ARGV[0]); if($g){ say "The student has gotten the grade $g for the score of $ARGV[0] +"; } else { say "Please enter a value between 0 and 100"; }

    Aaron B.
    My Woefully Neglected Blog, where I occasionally mention Perl.

Re: conditional statement
by locked_user sundialsvc4 (Abbot) on Apr 24, 2012 at 21:54 UTC

    Reads clear-enough to me.   “These aren’t the ’droids you’re looking for ... move along ... move along ...”