Perl Weekly Challenge 225: I’m back

This post presents my solutions to the Perl Weekly Challenge 225.
I know I’ve been not solving tasks for a while, a month or so, but the fact is that I recently changed my main job and therefore I was very busy in finishing up all the things at my previous job, as well as learning everything from scratch where I’m now!
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 225 - Task 1 - Raku Implementation

Given a list of sentences, where each word is separated by a single space, output the max counting of words in a sentence.

sub MAIN( *@sentences ) {
    my %data;
    %data{ $_ } = $_.split( /\s/ ).elems for @sentences;
    %data.values.max.say;
}



I soved with a simple hash that is keyed by the sentence and keep track of the word counting, then I select the max value.

PWC 225 - Task 2 - Raku Implementation

Given a list of integers, produce a left-right sum, which is kind of bizzarre.

sub MAIN( *@numbers where { @numbers.grep( * ~~ Int ).elems == @numbers.elems } ) {
    my ( @left, @right );

    @left.push: 0;
    @left.push: @numbers[ 0 .. $_ ].sum for 0 ..^ @numbers.elems - 1;

    @right.push: @numbers[ $_ .. * ].sum for 1 ..^ @numbers.elems;
    @right.push: 0;

    say @left;
    say @right;

    (@left Z[-] @right).map( { $_.abs } ).say;
}



I use the Z[-] operator to mix the arrays producing the difference, then I map the result into a only positive value.

PL/Perl Implementations

PWC 225 - Task 1 - PL/Perl Implementation

As usual, more verbose than its counterpart in Raku, but still a simple task. I keep track of the max value as long as I iterate across all the sentences:

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

   my $max = 0;

   for ( $sentences->@* ) {
       my $count = scalar split( /\s/, $_ );
       $max = $max > $count ? $max : $count;
   }

   return $max;
$CODE$
LANGUAGE plperl;



The trick here is to count, by means of scalar, the words in a splitted sentence.

PWC 225 - Task 2 - PL/Perl Implementation

A translation of the Raku implementation, but with a single final loop to zip the arrays:

CREATE OR REPLACE FUNCTION
pwc225.task2_plperl( int[] )
RETURNS SETOF int
AS $CODE$
   my ( $numbers ) = @_;

   my ( @left, @right );

   push @left, 0;
   for my $index ( 0 .. scalar( $numbers->@* ) - 2 ) {
       my $sum = 0;
       $sum += $_ for ( $numbers->@[ 0 .. $index ] );
       push @left, $sum;
   }

   for my $index ( 1 .. scalar( $numbers->@* ) - 1 ) {
       my $sum = 0;
       $sum += $_ for ( $numbers->@[ $index .. scalar( $numbers->@* )  ] );
       push @right, $sum;
   }

   for my $index ( 0 .. $#left ) {
       my $value = $left[ $index ] - $right[ $index ];
       $value = $value > 0 ? $value : $value * - 1;
       return_next( $value );
   }

return undef;


$CODE$
LANGUAGE plperl;



Note that since I iterate on @left I don’t need the final zero in the @right array.

PostgreSQL Implementations

PWC 225 - Task 1 - PL/PgSQL Implementation

Similar to the PL/Perl implementation, but I use the SQL to count the words since I can split a text into a table:

CREATE OR REPLACE FUNCTION
pwc225.task1_plpgsql( sentences text[] )
RETURNS int
AS $CODE$
DECLARE
	current_sentence text;
	max_length int := 0;
	current_length int := 0;
BEGIN
	FOREACH current_sentence IN ARRAY sentences LOOP
		SELECT count(*)
		INTO current_length
		FROM regexp_split_to_table( current_sentence, ' ' );

		IF current_length > max_length THEN
		   max_length := current_length;
		END IF;
	END LOOP;

RETURN max_length;
END
$CODE$
LANGUAGE plpgsql;



PWC 225 - Task 2 - PL/PgSQL Implementation

Similar to the PL/Perl implementation, makes usage of arrays and internal state.

CREATE OR REPLACE FUNCTION
pwc225.task2_plpgsql( numbers int[] )
RETURNS SETOF INT
AS $CODE$
DECLARE
	current_value int := 0;
	current_sum int := 0;

	current_index int := 0;
	current_sub_index int := 0;
	a_left int[];
	a_right int[];
BEGIN

	a_left := array_append( a_left, 0 );
	current_index := 0;
	FOR current_index IN 1 .. array_length( numbers, 1 ) - 1 LOOP
	    current_sum := 0;
	    FOR current_sub_index IN 1 .. current_index LOOP
	    	current_sum := current_sum + numbers[ current_sub_index ];
	    END LOOP;
	    a_left := array_append( a_left, current_sum );
	END LOOP;


	current_index := 0;
	FOR current_index IN 2 .. array_length( numbers, 1 )  LOOP
	    current_sum := 0;
	    FOR current_sub_index IN current_index .. array_length( numbers, 1 ) LOOP
	    	current_sum := current_sum + numbers[ current_sub_index ];
	    END LOOP;
	    a_right := array_append( a_right, current_sum );
	END LOOP;

        a_right := array_append( a_right, 0 );

	FOR current_index IN 1 .. array_length( a_left, 1 ) LOOP
	    current_value := a_left[ current_index ] - a_right[ current_index ];
	    IF current_value > 0 THEN
	       RETURN NEXT current_value;
	    ELSE
	       RETURN NEXT ( current_value * -1 );
	    END IF;
	END LOOP;

RETURN;

END
$CODE$
LANGUAGE plpgsql;



The article Perl Weekly Challenge 225: I'm back has been posted by Luca Ferrari on July 12, 2023