What is the easiest or most effective way to convert month's abbreviation to a number in Perl? (ie “jan” to 1)

StackOverflow https://stackoverflow.com/questions/241579

  •  04-07-2019
  •  | 
  •  

Question

If I import a library to use a method, would it be worth it? Does importing take up a lot of memory?

Was it helpful?

Solution

borrowed from here

%mon2num = qw(
    jan 1  feb 2  mar 3  apr 4  may 5  jun 6
    jul 7  aug 8  sep 9  oct 10 nov 11 dec 12
);

and to retrieve

$mon2num{"jan"}

OTHER TIPS

Here is yet another way to do it:

my %month; @month{qw/jan feb mar apr may jun
                     jul aug sep oct nov dec/} = (1 .. 12);

Importing such a module is not likely to cost that much memory that you should refrain from it, though in this case probably a simple hash would be just as good. Something like

my %number_for = (
    jan => 1,
    feb => 2,
#etc...
);
#...
do_something_with($number_for{$month})
my %month_num = do { my $i = 1; map {; $_ => $i++ } (
    qw( jan feb mar apr may jun jul aug sep oct nov dec )
) };

Or maybe:

my %month_num;
$month_num{ $_ } = 1 + keys %month_num for (
    qw( jan feb mar apr may jun jul aug sep oct nov dec )
);

Or using a zip function:

my %month_num = do {
    my @month = qw( jan feb mar apr may jun jul aug sep oct nov dec );
    zip2( 1 .. 1+$#month, @month );
};

Hmm - there seem to be plenty of overly complicated ways to do this. For something this simple clarity is key:

# create a lookup table of month abbreviations to month numbers
my %month_abbr_to_number_lkup = (
    jan => 1,
    feb => 2,
    mar => 3,
    apr => 4,
    may => 5,
    jun => 6,
    jul => 7,
    aug => 8,
    sep => 9,
    oct => 10,
    nov => 11,
    dec => 12,
);

# get the number for a month
my $number = $month_abbr_to_number_lkup{$abbr}
    || die "Could not convert month abbreviation '$abbr' to a number.";

Note also that hash keys are case sensitive; depending on where your abbreviations are coming from you may want to down-case them first to match the hash keys.

%mon_2_num = (jan => 1,
              feb => 2,
              ...);

$month_number = $mon_2_num{lc($month_name_abbrev)};

Another way to do this using a hash slice:

@month{qw(jan feb mar apr may jun jul aug sep oct nov dec)} = 1..12;

It depends on how much date manipulation you're intending to do. At first you're probably better off with hand-rolling it, e.g.

my @months = qw(Jan Feb Mar Apr May Jun
                Jul Aug Sep Oct Nov Dec);
my %monthnum = map { $_ => $months[ $_ - 1 ] } 1..12;

(I prefer this approach because it's comparatively obvious what you're doing - you have a list of months, then you map them from 1..12 (the numbers that make sense to a human) to 0..11 (the numbers that make sense to a computer). The performance bottlenecks in your code aren't going to be in this sort of code, they'll be in network, database or disc-accessing code, so concentrate on making your code readable.)

As you start adding to your code, you may find that a lot of this stuff is done already by existing modules, and it might be easier to do some of the simple stuff with e.g. Date::Calc. Or you may find a date/time module more suited to your needs; that's beyond the scope of this question.

Bear in mind also that some modules use autosplit, where only those parts of the module that are needed are loaded. Also, the main performance impact of using a large module isn't necessarily RAM, it's probably more likely to be the time/CPU overhead of loading and compiling it before any of your code has ever run.

Definitely a hash, as suggested by others.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top