4

I have the following array of references to arrays:

my @holidays = [[2012,'01','02'],[2012,'01','16'],[2012,'02','20'],[2012,'04','16'],[2012,'05','28'],[2012,'07','04'],[2012,'09','03'],[2012,'10','08'],[2012,'11','12'],[2012,'11','22'],[2012,'12','25']];

Which are IRS recognized legal holidays during 2012. I would like to match the array @dueDate to a value in that array and return 1 or true if it is present.

    while ($holidays[@dueDate]){
        print ("Found Holiday \t join('-',@dueDate)");
        @dueDate = Add_Delta_Days(@dueDate, 1);
        if ( Day_of_Week(@dueDate) > 5){
            @dueDate = Monday_of_Week((Week_Number(@dueDate)+1), $dueDate[0]);
        }
    }

Is my current attempt at this - the condition of the while statement is never true. I've tried a few different combinations of referencing and dereferencing holidays to no avail.

What would the best way be to manipulate the evaluation within the while statement such that the block executes when @dueDate contains a date within my array above.

Note: @dueDate is a Date::Calc standard array - (Year, Month, Day)

voteblake
  • 329
  • 1
  • 3
  • 11
  • How many elements does @dueDate contain? – Girish Rao Jun 12 '12 at 20:57
  • @dueDate contains 3 elements - Four digit year, two digit month, and two digit day. – voteblake Jun 12 '12 at 21:08
  • These are how the two variables are displayed in the Eclipse debugger at the invocation of the while statement: dueDate ... [0] 2012 [1] 1 [2] 11 @holidays ... [0] ARRAY(0x3567c78)... [0] ARRAY(0x356a4f0)... [0] 2012 [1] 01 [2] 02 [1] ARRAY(0x379d4f0)... [2] ARRAY(0x356b898)... [3] ARRAY(0x3567948)... [4] ARRAY(0x2a846d8)... [5] ARRAY(0x356bf88)... [6] ARRAY(0x2a84738)... [7] ARRAY(0x356bda8)... [8] ARRAY(0x356b880)... [9] ARRAY(0x356b8c8)... [10] ARRAY(0x356bd60)... – voteblake Jun 12 '12 at 21:11
  • 1
    Have you tried if (exists $holidays{@dueDate}) (not 100% sure about the syntax on @dueDate but try the exists function) – Girish Rao Jun 12 '12 at 21:12

4 Answers4

3

This should put you on the right track. Two problems I see with your code - an array of arrays should have normal parentheses on the outer part, and use the ~~ operator to compare arrays for equality.

my @holidays = ([2012,'01','02'],[2012,'01','16'],[2012,'02','20'],[2012,'04','16'],  
[2012,'05','28'],[2012,'07','04'],[2012,'09','03'],[2012,'10','08'],[2012,'11','12'], 
[2012,'11','22'],[2012,'12','25']);
my $i;
my @duedate = [2012, '01', '02'];

for ($i = 0; $i < @holidays; $i++)
{
    if (@holidays[$i] ~~ @duedate)
    {
        print "matched!!";
    }
}
PinkElephantsOnParade
  • 6,452
  • 12
  • 53
  • 91
  • 1
    Used this with the for loop from @fxzuz. Thanks for the help - I knew I was getting something wrong with the array syntax. – voteblake Jun 12 '12 at 21:29
  • 1
    hum, I see you accepted this solution. Keep in mind it's rather quite inefficient. It has to check every @holiday for a match. That's O(N) operations. Mine is O(1). No matter how many holidays you have, it just takes one check to see if a date is a holiday. – ikegami Jun 13 '12 at 02:00
2

First,

my @holidays = [[2012,'01','02'],...,[2012,'12','25']];

should be

my @holidays = ([2012,'01','02'],...,[2012,'12','25']);

You're creating an array with a single element.


Probably the best way to achieve what you want is to use a hash.

my %holidays = map { join('-', @$_) => 1 } @holidays;

Then all you need is

while ($holidays{join('-', @dueDate)}) {
   my $dow = Day_of_Week(@dueDate);
   @dueDate = Add_Delta_Days(@dueDate,
      $dow == 5 || $dow == 6 ? 8 - $dow : 1);
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
2

This is my answer, working on Perl 5.14, also I use smartmatching ~~ operator to compare two arrays.

You assign to array @holidays = [[2012,'01','02'], ]; isn't correct actually you assign anonymous array [ ['2012', '01', '02'], ] to first element of @holidays.

use v5.14;

my @holidays = ( ['2012', '01', '02'], ['2012', '01', '16'] );
my @due_date = ( '2012', '01', '16' );

for my $holiday (@holidays) {

    if (@$holiday ~~ @due_date) {
        say "holiday match";
    }
}
Pavel Vlasov
  • 3,455
  • 21
  • 21
0

Okay, a few things:

1: Lists are contained in parentheses, and literal array references are written between brackets. So, you should have:

my @holidays = ([2012,'01','02'],[2012,'01','16'],[2012,'02','20'],[2012,'04','16'],[2012,'05','28'], [2012,'07','04'],[2012,'09','03'],[2012,'10','08'],[2012,'11','12'],[2012,'11','22'],[2012,'12','25']);

2: When you look at $holidays[@dueDate], you're calling everything in scalar context. In particular, since @dueDate has three elements, you're only looking at $holidays[3].

3: Unless you're writing a piece of throwaway code, always use strict; and use warnings;.

So, you want something like this:

use strict;
use warnings;

my @holidays = ([2012,'01','02'],[2012,'01','16'],[2012,'02','20'],[2012,'04','16'],[2012,'05','28'],
    [2012,'07','04'],[2012,'09','03'],[2012,'10','08'],[2012,'11','12'],[2012,'11','22'],[2012,'12','25']);

my @dueDates=([2012,'01','01'],[2012,'01','02'],[2012,'01','03']); #Or whatever

my @due_dates_that_are_holidays=();

foreach my $due_date(@dueDates)
{
  foreach my $holiday(@holidays)
  {
    my ($h_y,$h_m,$h_d)=@$holiday; #Capturing year month and day from the array reference
    my ($d_y,$d_m,$d_d)=@$due_date; #Ditto for the due date

    if($h_y == $d_y and $h_m eq $d_m and $h_d eq $d_d)
    {
      push @due_dates_that_are_holidays,$due_date;
    }
  }
}
print join("-",@{$_}) . "\n" foreach(@due_dates_that_are_holidays);

The above code produces the following output:

2012-01-02