Advent Calendar - December 7, 2025

Sunday, Dec 7, 2025| Tags: Raku, Perl, PostgreSQL

Advent Calendar 2025

|   Day 6   |   Day 7   |   Day 8   |


The gift is presented by Luca Ferrari. Today he is talking about his solution to The Weekly Challenge - 309. This is re-produced for Advent Calendar 2025 from the original post.



This post presents my solutions to the Perl Weekly Challenge 309.

I keep doing the Perl Weekly Challenge in order to mantain my coding skills in good shape, as well as in order to learn new things, with particular regard to Raku, a language that I love.

This week, I solved the following tasks:

The PL/Perl implementations are very similar to a pure Perl implementation, even if the PostgreSQL environment could involve some more constraints. Similarly, the PL/PgSQL implementations help me keeping my PostgreSQL programming skills in good shape.

Raku Implementations



PWC 309 - Task 1 - Raku Implementation

Given a sorted array of integers, find out the integer that has the min differences from the previous one.


sub MAIN( *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {
    my %gaps;
    for 1 ..^ @nums.elems {
        %gaps{ @nums[ $_ ] - @nums[ $_ - 1 ] } = @nums[ $_ ];
    }

    %gaps{ %gaps.keys.min }.say;
}

I populate an hash of %gaps with the difference between elements, and value as the element, so that it does just suffice to extract the min key of the has to get the value. Please note that duplicated differences are overwritten, so only the last smallest difference is kept.


PWC 309 - Task 2 - Raku Implementation

Given an array of integers, find out the smallest difference between any element of the array.


sub MAIN( *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {

    my $min = Inf;
    for @nums -> $current {
        my $found = @nums
                 .grep( * != $current )
                 .map( { abs( $current - $_.Int ) } )
                 .min;
        $min = $found if $min > $found;
    }

    $min.say;
}

I iterate over element of the array, and then grep for all other elements, mapping each one to the difference and extracting the min value. If the min is less than the initial one, or previous one, I keep this, otherwise go to the next element.


PL/Perl Implementations



PWC 309 - Task 1 - PL/Perl Implementation

Essentially, this is the same implementation as in Raku.


CREATE OR REPLACE FUNCTION
pwc309.task1_plperl( int[] )
RETURNS int
AS $CODE$

   my ( $nums ) = @_;
   my $gaps = {};

   for my $index ( 1 .. $nums->@* - 1 ) {
       $gaps->{ $nums->@[ $index ] - $nums->@[ $index - 1 ] } = $nums->@[ $index ];
   }

   return $gaps->{ ( sort( keys $gaps->%* ) )[0] };

$CODE$
LANGUAGE plperl;

PWC 309 - Task 2 - PL/Perl Implementation

Same solution as in Raku.


CREATE OR REPLACE FUNCTION
pwc309.task2_plperl( int[] )
RETURNS int
AS $CODE$

   my ( $nums ) = @_;
   my $min;

   for my $current ( $nums->@* ) {

       my $current_min = (
                       sort
                       map { $_ > $current ? $_ - $current : $current - $_ }
                       grep { $_ != $current }
                       $nums->@* )[ 0 ];

      if ( ! $min || $current_min < $min ) {
           $min = $current_min;
      }
   }

   return $min;

$CODE$
LANGUAGE plperl;

I use sort on the resulting list to get out the min value.


PostgreSQL Implementations



PWC 309 - Task 1 - PL/PgSQL Implementation

A single query with window functions make the deal to find out, for each value, the difference with the next one, hence the min difference.


CREATE OR REPLACE FUNCTION
pwc309.task1_plpgsql( nums int[] )
RETURNS int
AS $CODE$

   WITH data AS (
       SELECT v, v - lag( v, 1, v * -10 ) over () AS diff
    FROM unnest( nums ) v
    ORDER BY diff ASC
   )
   SELECT  v
   FROM data

   LIMIT 1;

$CODE$
LANGUAGE sql;

PWC 309 - Task 2 - PL/PgSQL Implementation

In this implementation I iterate over the array elements and compute the differences.


CREATE OR REPLACE FUNCTION
pwc309.task2_plpgsql( nums int[] )
RETURNS int
AS $CODE$
DECLARE

    diff int;
    current_diff int;
    l int;
    r int;
BEGIN
    FOR l IN SELECT v FROM unnest( nums ) v LOOP
        for r IN SELECT v FROM unnest( nums ) v LOOP
            IF r = l THEN
           CONTINUE;
        END IF;

            current_diff := r - l;
        IF current_diff < 0 THEN
           current_diff := current_diff * -1;
        END IF;

        IF diff IS NULL OR current_diff < diff THEN
           diff := current_diff;
        END IF;
        END LOOP;

    END LOOP;

    RETURN diff;

END
$CODE$
LANGUAGE plpgsql;


If you have any suggestion then please do share with us perlweeklychallenge@yahoo.com.

|   Advent Calendar 2025   |

SO WHAT DO YOU THINK ?

If you have any suggestions or ideas then please do share with us.

Contact with me