Perl Weekly Challenge 196: Merry Christmas!
This post presents my solutions to the Perl Weekly Challenge 196.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:
- PWC 196 - Task 1 - Raku
- PWC 196 - Task 2 - Raku
- PWC 196 - Task 1 in PostgreSQL PL/Perl
- PWC 196 - Task 2 in PostgreSQL PL/Perl
- PWC 196 - Task 1 in PostgreSQL PL/PgSQL
- PWC 196 - Task 2 in PostgreSQL PL/PgSQL
PWC 196 - Task 1 - Raku Implementation
In the first there was a given input list of integers, and I need to find out any triplet that respect the1-2-3
rule, that is the leftmost must be less than middle one that, in turn has to be less than the rightmost number.
sub MAIN( *@list where { @list.grep( * ~~ Int ).elems == @list.elems } ) {
my @found;
my $last = 0;
for @list.rotor( 3, :partial ) -> $triplet {
next if $triplet.elems != 3;
@found.push: $triplet if ( $triplet[ 0 ] < $triplet[ 1 ] < $triplet[ 2 ] );
}
@found.join( "\n" ).say;
}
I use a
rotor
to extract triplets, and skip all of them that are not complete since the input array could not be a multiple of three.
Then I keep the triplet into the @found
array only if the triplet satisfies the 1-2-3
rule. Note how easy and short it is to exrepss a double disequation in Raku!
PWC 196 - Task 2 - Raku Implementation
Again a list of integers, sorted this time. The task required to find out all the indexes that indicate a natural number sequence within the input list.sub MAIN( *@list where { @list.grep( * ~~ Int ).elems == @list.elems } ) {
my @ranges;
my $start = -1;
my $end = -1;
for 0 .. @list.elems {
next if ! $_;
next if $_ <= $end;
$start = $_;
$end = $start;
$end++ while ( $end < @list.elems && @list[ $end + 1 ] == @list[ $end ] + 1 );
@ranges.push: [ $start, $end ] if ( $start < $end );
}
@ranges.join( "\n" ).say;
}
I iterate over the input
@list
and keep track of the current position into $start
, then I try to increment the $end
indg index checking if the righter value is increased by one with regard to the current one. If I do have two different indexes, I keep them as an array into the @ranges
set of results, that I then print.
PWC 196 - Task 1 - PL/Perl Implementation
Straightforward implementation like the Raku approach:CREATE OR REPLACE FUNCTION
pwc196.task1_plperl( int[] )
RETURNS SETOF int[]
AS $CODE$
my ( $array ) = $_[ 0 ];
my $index = 1;
while ( $index < $array->@* ) {
my @triplet = ( $array->[ $index - 1 ], $array->[ $index ], $array->[ $index + 1 ] );
$index += 2 and return_next( [ @triplet ] ) if ( $tripet[ 0 ] < $triplet[ 1 ]
&& $triplet[ 1 ] < $triplet[ 2 ] );
$index++;
}
return undef;
$CODE$
LANGUAGE plperl;
Note that I increment
$index
by two before returning a new result into the result set, so that when the routine resumes the $index
is increased by another unit and skips therefore a triplet, if found.
PWC 196 - Task 2 - PL/Perl Implementation
Similar implementation to the Raku one:CREATE OR REPLACE FUNCTION
pwc196.task2_plperl( int[] )
RETURNS SETOF int[]
AS $CODE$
my ( $array ) = $_[0];
my ( $start, $end ) = ( 0, 0 );
while ( $start < $array->@* ) {
$end = $start;
$end++ while ( $end < $array->@* && $array->[ $end + 1 ] == $array->[ $end ] + 1 );
return_next( [ $start, $end ] ) if ( $end > $start );
$start += $end + 1;
}
return undef;
$CODE$
LANGUAGE plperl;
PWC 196 - Task 1 - PL/PgSQL Implementation
Same idea as the Raku and PL/Perl implementation: if the array triplets do the1-2-3
rule I append them to the result set, otherwise I go forward in seeking for a new triplet.
CREATE OR REPLACE FUNCTION
pwc196.task1_plpgsql( l int[] )
RETURNS SETOF int[]
AS $CODE$
DECLARE
last_index int := 0;
BEGIN
FOR i IN 1 .. array_length(l,1) - 1 LOOP
IF i <= last_index THEN
CONTINUE;
END IF;
IF l[ i - 1 ] < l[ i ] AND l[ i ] < l[ i + 1 ] THEN
RETURN NEXT ARRAY[ l[i-1], l[i], l[i + 1] ]::int[];
last_index := i + 1;
END IF;
END LOOP;
RETURN;
END
$CODE$
LANGUAGE plpgsql;
PWC 196 - Task 2 - PL/PgSQL Implementation
A more verbose but conceptually identical implementation to the PL/Perl solution:CREATE OR REPLACE FUNCTION
pwc196.task2_plpgsql( l int[])
RETURNS SETOF int[]
AS $CODE$
DECLARE
c_start int := 0;
c_end int := 0;
BEGIN
FOR i IN 0 .. array_length( l, 1 ) LOOP
IF i < c_end THEN
CONTINUE;
END IF;
c_start := i;
c_end := c_start;
WHILE c_end < array_length( l, 1 ) AND l[ c_end + 1 ] = l[ c_end ] + 1 LOOP
c_end := c_end + 1;
END LOOP;
IF c_start < c_end THEN
RETURN NEXT ARRAY[ c_start, c_end ]::int[];
END IF;
END LOOP;
RETURN;
END
$CODE$
LANGUAGE plpgsql;