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

I have two questions.. You can see what I'm trying to do below and it's really bulky and dirty and it takes forever to edit. Can someone show me a way I can do the same thing but with less elsifs? I've found a lot of my scripts have quite a bit repetitive code I'd like to get rid of. Are there any good tutorials around that will help reduce these nuissances?

Thanks for your time!

if ($realmonth eq "1" || $realmonth eq "01") { print "January"; } elsif($realmonth eq "2" || $realmonth eq "03") { print "February"; } elsif($realmonth eq "3" || $realmonth eq "03") { print "March"; } elsif($realmonth eq "4" || $realmonth eq "04") { print "April"; } elsif($realmonth eq "5" || $realmonth eq "05") { print "May"; } elsif($realmonth eq "6" || $realmonth eq "06") { print "June"; } elsif($realmonth eq "7" || $realmonth eq "07") { print "July"; } elsif($realmonth eq "8" || $realmonth eq "08") { print "August"; } elsif($realmonth eq "9" || $realmonth eq "09") { print "September"; } elsif($realmonth eq "10") { print "October"; } elsif($realmonth eq "11") { print "November"; } elsif($realmonth eq "12") { print "December"; }


"Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

sulfericacid

Replies are listed 'Best First'.
Re: Reducing repetitive code
by duff (Parson) on Jan 06, 2004 at 16:30 UTC

    First off, you have an error in February's conditional. Secondly, you could take advantage of perl's if-it-looks-like-a-number-it-is and do this:

    my @months = qw(January February March April May June July August Sept +ember October November December); print $months[$realmonth-1];

    Thirdly, since you're dealing with dates, you should probably be using one of the DateTime modules or at least POSIX::strftime.

    Update: Fixed the off-by-one error in my array index.

Re: Reducing repetitive code
by dragonchild (Archbishop) on Jan 06, 2004 at 16:34 UTC
    Use an array or a hash. Personally, I'd use an hash here, for the ease of error-handling and the fact that your indices don't begin at 0.
    my %month_names = do { my $i = 1; map { sprintf("%02d", $i++) => $_ } qw( January Feburary March April May June July August September October November December ) }; sub get_monthname { my ($month_num) = @_; $month_num = sprintf("%02d", $month_num); return $month_names{$month_num}; }

    Now, the nice thing is that if you pass in something like '13' or 'aaa', it will return undef. (It will also throw a warning with the 'aaa' one, but you can bypass that with a well-placed no warnings 'number'.) And, it will do the right thing with '1', '01', and '0001'.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      A hash was my first thought, too, but after reading duff's solution, I think an array is better. The lookup time will be faster, and the off-by-one problem is trivial to get around. Perl will numify '01' and '1' to the same thing, so there's no problem there. Also, it's easier to build the array than it is to map the months into a hash.

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      : () { :|:& };:

      Note: All code is untested, unless otherwise stated

        An array is better ... except that
        • all non-numbers will return 'January'.
        • 1234567890 will blow your memory out of the water with an array, but will behave with a hash.
        • -2 will behave non-deterministically. (If it's the first run, will return November. But, if you tried 13, it will then return December.)
        • -40 will die a horrible death.

        Now, my complaints originate from having to be defensive. If you can assume that my complaints won't occur, then, by all mean, use an array for speed and intuitiveness.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        dragonchilds' concerns are quite valid, and easily handled while keeping to a simple array:
        if ( $realmonth >0 and $realmonth <=12 ) { print $monthname[$realmonth-1]; } else { warn "Invalid value for realmonth: $realmonth\n"; }
Re: Reducing repetitive code
by broquaint (Abbot) on Jan 06, 2004 at 16:36 UTC
    Code like that is usually prime for a hash e.g
    # a zip() function would be handy here (see. Language::Functional) my $i = 1; my %months = map { $i++ => $_ } qw(January February March April May June July August September October November December); printf "%2s: %s\n", $_, $months{ sprintf '%d', $_ } for qw( 09 4 06 11 ); __output__ 09: September 4: April 06: June 11: November
    HTH

    _________
    broquaint

Re: Reducing repetitive code
by davido (Cardinal) on Jan 06, 2004 at 17:23 UTC
    Here's a concise version that uses a hash, a hash slice, and substitution.
    my %months; @months{1..12} = qw/January February March April May June July August September October November December/; my $numeric_month = "01"; # Test case. my $string_month; $numeric_month =~ s/0(\d)/$1/; if ( exists( $months{$numeric_month} ) ) { $string_month = $months{$numeric_month} } else { die "Invalid month format.\n"; }

    Dave

Re: Reducing repetitive code
by Paulster2 (Priest) on Jan 06, 2004 at 21:37 UTC

    I didn't see it mentioned above, so will mention the mod Date::Manip that will save you a ton of repetitive motions with anything to do with dates. You can use just about any type of manipulation that you would like. With it you can pretty much eliminate setting up arrays with month names (October, November, ...), or names of the days (Tuesday, Wednesday, Thursday, ...) or anything having to do with dates. Read the perldoc on it and you will find it quite comprehensive. I find the perldoc so comprehensive, infact, I use it to get the formating I can never seem to remember with using date on UNIX systems. Check it out, I believe that you will like it.



    UPDATE: Fixed the CPAN link.

    Paulster2

Re: Reducing repetitive code
by artist (Parson) on Jan 06, 2004 at 18:34 UTC
    Perhaps the following will help you for the bigger picture you are trying to solve:

    use DateTime; $dt = DateTime->now; $month_name = $dt->month_name;
    It prints full names of month as you desired.

Re: Reducing repetitive code
by cLive ;-) (Prior) on Jan 06, 2004 at 19:58 UTC
    my @months = qw(January February March April May June July August September October November December); print $months[$realmonth-1];

    .02

    cLive ;-)