Perl Weekly Challenge 326.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 326.

Task 1: Day of the Year

Submitted by: Mohammad Sajid Anwar
You are given a date in the format YYYY-MM-DD.

Write a script to find day number of the year that the given date represent.


Example 1
Input: $date = '2025-02-02'
Output: 33

The 2nd Feb, 2025 is the 33rd day of the year.

Example 2
Input: $date = '2025-04-10'
Output: 100

Example 3
Input: $date = '2025-09-07'
Output: 250

According to the Gregorian calendar, if the year number is a multiple of 4 the year is a leap year, unless it is a multiple of 100, when it is not a leap year, unless it is a multiple of 400, when it is. So it is simple to find out if February within a given year has 28 or 29 days. First I compute a list of days to the beginning of each month in ordinary years:

perl -MList::Util=reductions -E '
@m=(0,31,28,31,30,31,30,31,31,30,31,30,31); say join ",",reductions {$a+$b} @m;'

Results:

0,31,59,90,120,151,181,212,243,273,304,334,365

I used reductions from List::Util to add all days up to the beginning of each month.

With that list I can easily parse the ISO date obtain the starting day number for the month, add the day of the month, and add 1 after February for leap years. The result fits a two liner.

Examples:

perl -E '
@s=(0,0,31,59,90,120,151,181,212,243,273,304,334);for(@ARGV){($y,$m,$d)=split "-";
say "$_ -> ", $s[$m]+$d+($m>2&&$_%4==0&&($_%100||$_%400==0)?1:0);}
' 2025-02-02 2025-04-10 2025-09-07

Results:

2025-02-02 -> 33
2025-04-10 -> 100
2025-09-07 -> 250

Unfortunately, these examples don’t test leap years, as 2025 is not multiple of 4. So I make a few additional examples:

perl -E '
@s=(0,0,31,59,90,120,151,181,212,243,273,304,334);for(@ARGV){($y,$m,$d)=split "-";
say "$_ -> ", $s[$m]+$d+($m>2&&$_%4==0&&($_%100||$_%400==0)?1:0);}
' 2024-02-01 2024-03-01 2025-03-01 2100-03-01 2400-03-01

Results:

2024-02-01 -> 32
2024-03-01 -> 61
2025-03-01 -> 60
2100-03-01 -> 60
2400-03-01 -> 61

The first line shows that being in a leap year doesn’t affect dates in February, the second shows that it does affect March, as verified by a comparison to the third line, as 2025 is not a leap year, not being a multiple of 4. The fourth line is consistent with 2100 not being a leap year, even as it is a multiple of 4, since it is also a multiple of 100. Finally, the fifth line is consistent with 2400 being a leap year, even as it is a multiple of 100, since it is also a multiple of 400.

The full code is less obscure and adds a few tests.

 1  # Perl weekly challenge 326
 2  # Task 1:  Day of the Year
 3  #
 4  # See https://wlmb.github.io/2025/06/16/PWC326/#task-1-day-of-the-year
 5  use v5.36;
 6  use List::Util qw(reductions);
 7  die <<~"FIN" unless @ARGV;
 8      Usage: $0 D1 D2...
 9      to find the day number corresponding to the ISO dates D1, D2.
10      FIN
11  my @days_in_month=(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
12  my @offsets=(0, reductions {$a+$b} @days_in_month);
13  for(@ARGV){
14      say("Wrong format: $_"), next unless /^(\d{4})-(\d{2})-(\d{2})$/;
15      my ($year, $month, $day_of_month)=($1, $2, $3);
16      say("Wrong month: $_"), next unless 1 <= $month <= 12;
17      say("Wrong day: $_"), next
18          unless 1 <= $day_of_month
19              && ($day_of_month <= $days_in_month[$month] || $month == 2 && $day_of_month <= 29);
20      my $leap=$year%4==0;
21      $leap=0 if $year%100 == 0;
22      $leap=1 if $year%400 == 0;
23      my $day_of_year = $offsets[$month] + $day_of_month;
24      ++$day_of_year if $leap and $month >= 3;
25      say "$_ -> $day_of_year";
26  }
27  

Example:

./ch-1.pl 2025-02-02 2025-04-10 2025-09-07 2024-02-01 2024-03-01 2025-03-01 2100-03-01 2400-03-01

Results:

2025-02-02 -> 33
2025-04-10 -> 100
2025-09-07 -> 250
2024-02-01 -> 32
2024-03-01 -> 61
2025-03-01 -> 60
2100-03-01 -> 60
2400-03-01 -> 61

Task 2: Decompressed List

Submitted by: Mohammad Sajid Anwar
You are given an array of positive integers having even elements.

Write a script to to return the decompress list. To decompress, pick
adjacent pair (i, j) and replace it with j, i times.


Example 1
Input: @ints = (1, 3, 2, 4)
Output: (3, 4, 4)

Pair 1: (1, 3) => 3 one time  => (3)
Pair 2: (2, 4) => 4 two times => (4, 4)

Example 2
Input: @ints = (1, 1, 2, 2)
Output: (1, 2, 2)

Pair 1: (1, 1) => 1 one time  => (1)
Pair 2: (2, 2) => 2 two times => (2, 2)

Example 3
Input: @ints = (3, 1, 3, 2)
Output: (1, 1, 1, 2, 2, 2)

Pair 1: (3, 1) => 1 three times => (1, 1, 1)
Pair 2: (3, 2) => 2 three times => (2, 2, 2)

I use for_list to iterate over the i,j pairs. I use the repetation operator x to build the resulting list. This yields a half-liner.

Example 1:

perl -E '
for my($i,$j)(@ARGV){push @o, ($j)x$i} say "@ARGV -> @o"
' 1 3 2 4

Results:

1 3 2 4 -> 3 4 4

Example 2:

perl -E '
for my($i,$j)(@ARGV){push @o, ($j)x$i} say "@ARGV -> @o"
' 1 1 2 2

Results:

1 1 2 2 -> 1 2 2

Example 3:

perl -E '
for my($i,$j)(@ARGV){push @o, ($j)x$i} say "@ARGV -> @o"
' 3 1 3 2

Results:

3 1 3 2 -> 1 1 1 2 2 2

The full code is similar.

 1  # Perl weekly challenge 326
 2  # Task 2:  Decompressed List
 3  #
 4  # See https://wlmb.github.io/2025/06/16/PWC326/#task-2-decompressed-list
 5  use v5.36;
 6  die <<~"FIN" unless @ARGV and @ARGV%2==0;
 7      Usage: $0 R1 N1 R2 N2...
 8      to make a list with number Ni repeated Ri times.
 9      FIN
10  my @output=();
11  for my($i,$j)(@ARGV){
12      push @output, ($j)x$i;
13  }
14  say "@ARGV -> @output"

Examples:

./ch-2.pl 1 3 2 4
./ch-2.pl 1 1 2 2
./ch-2.pl 3 1 3 2

Results:

1 3 2 4 -> 3 4 4
1 1 2 2 -> 1 2 2
3 1 3 2 -> 1 1 1 2 2 2

/;

Written on June 16, 2025