in reply to Reducing repetitive code

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.

Replies are listed 'Best First'.
Re: Re: Reducing repetitive code
by hardburn (Abbot) on Jan 06, 2004 at 17:14 UTC

    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.

        Hmm, all of those could be solved by doing proper input validation. Also, for your second point, just indexing the array doesn't grow it, at least not on my version of perl:

        $ perl -MDevel::Size -e '@a = (0 .. 11); print Devel::Size::total_size +(\@a)' 296 $ perl -MDevel::Size -e '@a = (0 .. 11); $i = $a[56788]; print Devel:: +Size::total_size(\@a)' 296 # Just to make sure perl doesn't optimize away the assignment $ perl -MO=Deparse -MDevel::Size -e '@a = (0 .. 11); $i = $a[56788]; p +rint Devel::Size::total_size(\@a)' -e syntax OK use Devel::Size; @a = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); $i = $a[56788]; print Devel::Size::total_size(\@a); $ perl -v This is perl, v5.8.0 built for MSWin32-x86-multi-thread (with 1 registered patch, see perl -V for more detail) Copyright 1987-2002, Larry Wall Binary build 806 provided by ActiveState Corp. http://www.ActiveState. +com Built 00:45:44 Mar 31 2003 # snip the rest

        What would grow the array is autovivification, such as if you said $i = $a[57874]{key};.

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

      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"; }