Perl Weekly Challenge: Got a date with compression!

Looking at this week’s challenge, the “date” aspect jumped out at me, and I thought of a an old song… Got a Date With an Angel.

So let’s get on our way to heaven with Perl Weekly Challenge 326.

Task 1: Day of the Year

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

Approach

When I saw this as a problem, my first thought was “This is a method in every decent DateTime module. Does Mohammed want us to roll our own?” Then my immediate next thought was of the infamous “Falsehoods Programmers Believe About Time” article, and I said to myself “No. I write these solutions not to prove how clever a programmer I am, I write them to show how easy these languages are to solve problems in.” There’s nothing gained by trying to implement this by what? Doing what I did for PWC 227 and starting with the first day of the year and incrementing until I get to the target date? So here’s the really short answers.

Raku

In Raku, the day-of-year method from the Datish role does the work.

Date.new($date).day-of-year;

View the entire Raku script for this task on GitHub.

$ raku/ch-1.raku
Example 1:
Input: $date = '2025-02-02'
Output: 33

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

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

Perl

In Perl, we use the core module Time::Piece. We add one to the result because, according to the documentation, 0 = Jan 01.

use Time::Piece;
Time::Piece->strptime($date, "%Y-%m-%d")
           ->truncate(to => 'day')
           ->day_of_year + 1;

View the entire Perl script for this task on GitHub.

Python

In Python, we load the datetime module. There isn’t a method to get the day of the year from that, but the strftime method supports the %j directive (as the 1989 C standard requires). But this returns a “zero-padded decimal number” (a string, really), so I’m pushing it through int() to get rid of those zeros.

from datetime import date
int(date.fromisoformat(dateStr).strftime('%j'))

View the entire Python script for this task on GitHub.

Elixir

In Elixir, it’s all done by the Date stuct, and its functions from_iso8601!/2 and day_of_year/1.

Date.from_iso8601!(dateStr) |> Date.day_of_year

View the entire Elixir script for this task on GitHub.


Task 2: Decompressed List

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)

Approach

This is a pretty easy problem, especially when there are operators to do most of the work.

Raku

In Raku, there’s the list repetition operator (xx). And we can also show off processing a list by pairs.

sub decompress(@ints) {
  my @out;
  for @ints -> $i, $j {
    @out.append($j xx $i);
  }
  @out
} 

View the entire Raku script for this task on GitHub.

$ raku/ch-2.raku
Example 1:
Input: @ints = (1, 3, 2, 4)
Output: (3, 4, 4)

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

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

Perl

I keep forgetting that the x operator in Perl can not only be used to do string repetition, but if the x is in list context, and the left operand is either enclosed in parentheses or a qw// list, it performs a list repetition!

sub decompress(@ints) {
  my @out;
  for my ($i, $j) ( @ints ) {
    push @out, ($j) x $i;
  }
  @out
}

View the entire Perl script for this task on GitHub.

Python

In Python, version 3.12 added the batched function to itertools, which was a good enough reason for me to do a pyenv install 3.13.0, since I’ve been using 3.10.4 for much too long. However, this produces nested arrays, so to flatten them, I needed itertoolschain.from_iterable.

def decompress(ints):
  out = []
  for i, j in batched(ints, 2):
    out.append([j] * i)
  return list(chain.from_iterable(out))

View the entire Python script for this task on GitHub.

Elixir

As always, recursion is doing the looping. List.pop_at/3 is pulling the elements off the list, and List.duplicate/2 is doing the list repetition.

  def decompress([], out), do: out

  def decompress(ints, out) do
    {i, ints} = List.pop_at(ints, 0)
    {j, ints} = List.pop_at(ints, 0)
    decompress(ints, out ++ List.duplicate(j, i))
  end

  def decompress(ints) do
    decompress(ints, [])
  end

View the entire Elixir script for this task on GitHub.


Here’s all my solutions in GItHub: https://github.com/packy/perlweeklychallenge-club/tree/master/challenge-326/packy-anderson