Perl Weekly Challenge 250: the first one of 2024!

This post presents my solutions to the Perl Weekly Challenge 250.
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 250 - Task 1 - Raku Implementation

Given an array of integers, find out the smallest index where index mod 10 == nums[ index ].

sub MAIN( *@nums where { @nums.elems == @nums.grep( * ~~ Int ).elems } ) {
    $_.say and exit if ( @nums[ $_ ] == ( $_ % 10 ) ) for 0 ..^ @nums.elems;
    '-1'.say;
}



I loop over all the possible indexes, test the condition and print the index. If I found one, I exit, otherwise the catchall -1 value is printed.

PWC 250 - Task 2 - Raku Implementation

Given an array of alphanumeric stuff, either numbers or letters, calculate the max string value assuming that:
  • for a string the value is its own length;
  • for a digit-only string it is its numerical value.


sub MAIN( *@words ) {
    @words.map( { $_ ~~ / ^ <[0..9]>+ $ / ?? $_.Int !! $_.chars } ).max.say;
}



This is one of those rare cases where the second task is simpler than the first one: I remap the array of words into their numerical values. If the current word is made only by digits, I convert it into an integer, otherwise I compute its length. Then I keep the max value.

PL/Perl Implementations

PWC 250 - Task 1 - PL/Perl Implementation

A single loop does suffice to find out the smallest index, since I loop from the first one and exit the function as soon as I find one.

CREATE OR REPLACE FUNCTION
pwc250.task1_plperl( int[] )
RETURNS int
AS $CODE$
   my ( $nums ) = @_;

   for  ( 0 .. $nums->@* - 1 ) {
       return $_ if ( ( $_ % 10 ) == $nums->@[ $_ ] );
   }

   return -1;
$CODE$
LANGUAGE plperl;



PWC 250 - Task 2 - PL/Perl Implementation

Similar idea to the Raku approach: if it looks like a number, convert the string into a number, otherwise compute the length.

CREATE OR REPLACE FUNCTION
pwc250.task2_plperl( text[] )
RETURNS int
AS $CODE$
   my ( $words ) = @_;
   my $max = 0;

   for ( $words->@* ) {
       my $value = 0;

       if ( $_ =~ / ^ \d+ $ /x ) {
       	  $value = int( $_ );
       }
       else {
       	  $value = length( $_ );
       }

       $max = $value if ( $value > $max );

   }

   return $max;
$CODE$
LANGUAGE plperl;



PostgreSQL Implementations

PWC 250 - Task 1 - PL/PgSQL Implementation

Quite short implementation: I loop on every index and check if the modulus is a good value, stopping at the very first index found.

CREATE OR REPLACE FUNCTION
pwc250.task1_plpgsql( nums int[] )
RETURNS int
AS $CODE$
BEGIN
	FOR i IN 1 .. array_length( nums, 1 ) LOOP
	    IF  mod( i, 10 ) = nums[ i ] THEN
	    	RETURN i;
	    END IF;
	END LOOP;

	RETURN -1;
END
$CODE$
LANGUAGE plpgsql;



PWC 250 - Task 2 - PL/PgSQL Implementation

Here I decided to use a temproary table to store the word w, its length l and its numerical value v. At first I insert the word and its length, then I update every looks-like a number entry with its value, and then select the max value I find in the table.

CREATE OR REPLACE FUNCTION
pwc250.task2_plpgsql( words text[] )
RETURNS int
AS $CODE$
DECLARE
	final int;
BEGIN
	CREATE TEMPORARY TABLE IF NOT EXISTS t_values( w text, l int, v int DEFAULT 0 );
	TRUNCATE t_values;

	INSERT INTO t_values( w, l, v )
	SELECT vv, length( vv ), length( vv )
	FROM unnest( words ) vv;

	UPDATE t_values
	SET v = w::int
	WHERE w IN ( SELECT w FROM t_values
	      	     WHERE regexp_match( w, '^\d+$' ) IS NOT NULL );

	SELECT max( v )
	INTO final
	FROM t_values;

	RETURN final;
END
$CODE$
LANGUAGE plpgsql;



Python Implementations

PWC 250 - Task 1 - Python Implementation

The approach is the same as in Raku, with the extra work of converting every value into an integer.

import sys

# task implementation
def main( argv ):
    for i in range(0,len(argv)):
        if int(i) % 10 == int( argv[ i ] ):
            return i

    return -1


# invoke the main without the command itself
if __name__ == '__main__':
    print( main( sys.argv[ 1: ] ) )


PWC 250 - Task 2 - Python Implementation

I use a compiled regex to match what it looks like a number, and in such case I convert it into an integer, otherwise compute the length.

import sys
import re

# task implementation
def main( argv ):
    max = 0
    is_num = re.compile( '^\d+$' )
    for current in argv:
        v = 0

        if is_num.match( current ) is None:
            v = len( current )
        else:
            v = int( current )

        if v > max:
            max = v

    return max


# invoke the main without the command itself
if __name__ == '__main__':
    print( main( sys.argv[ 1: ] ) )


The article Perl Weekly Challenge 250: the first one of 2024! has been posted by Luca Ferrari on January 4, 2024