Perl Weekly Challenge 210: I didn’t get very well!
This post presents my solutions to the Perl Weekly Challenge 210.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 210 - Task 1 - Raku
- PWC 210 - Task 2 - Raku
- PWC 210 - Task 1 in PostgreSQL PL/Perl
- PWC 210 - Task 2 in PostgreSQL PL/Perl
- PWC 210 - Task 1 in PostgreSQL PL/PgSQL
- PWC 210 - Task 2 in PostgreSQL PL/PgSQL
Raku Implementations
PWC 210 - Task 1 - Raku Implementation
The first task was about implementing a kill and ring game, where an input array of integers is trimmed in steps and every number cut off increments the total score.sub MAIN( *@list is copy where { @list.grep( * ~~ Int).elems == @list.elems } ) {
my @removed;
for 2 .. @list.max {
next if @removed.grep( * == $_ );
next if @removed.grep( * == ( $_ + 1 ) );
next if @removed.grep( * == ( $_ - 1 ) );
@removed.push: @list.grep( * == $_ ), @list.grep( * == ( $_ + 1 ) ), @list.grep( * == ( $_ - 1 ) );
}
@removed.sum.say;
}
My understanding of the problem, that could have been solved by means of a simple sum over all the elements of the array, is that at every step I pick a number, and see if it has a plus/minus value, then I can kill the tuple made by the number and its plus/minus one counterparts. The sum of the erased number accumulates into the score. In order to do the above, I pushed all the lists into the
@removed
one, since I knew that after all I’m going to erase all of them. Then, iut is only a matter of summing the values.
PWC 210 - Task 2 - Raku Implementation
The second task was about moving numbers from left to right or viceversa in an array: if the number is negative it moves one place left, otherwise it moves one place right. When a number moves, it collides with another one and that with the minimum absolute value explodes, that means it is erased from the array.sub MAIN( *@list is copy where { @list.grep( * ~~ Int ).elems == @list.elems } ) {
my $move = True;
while ( $move ) {
$move = False;
for 0 ..^ @list.elems - 1 {
my ( $left, $right ) = @list[ $_ ], @list[ $_ + ( @list[ $_ ] > 0 ?? 1 !! -1 ) ];
next if ( ! $left || ! $right );
next if ( $left > 0 && $right > 0 );
next if ( $left < 0 && $right < 0 );
$move = True;
@list[ $_ + ( @list[ $_ ] > 0 ?? 1 !! -1 ) ] = Nil if ( $left.abs >= $right.abs );
@list[ $_ ] = Nil if ( $left.abs <= $right.abs );
}
@list = @list.grep( * ~~ Int );
}
@list.grep( * ~~ Int ).join( ', ' ).say;
}
I implemented as follows:
$left
and$right
are the two numbers I’m going to analyze at every step;- if the numbers have both the same sign, then no move happens, so continue to the next iteration;
- otherwise a
$move
is necessary, and I set toNil
the number that has to explode. Since if the numbers are the same, in absolute value, both must explode, I test with less-or-equal and greater-or-equal.
Nil
values.
PL/Perl Implementations
PWC 210 - Task 1 - PL/Perl Implementation
Same implementation as in Raku, a little more verbose because I need some other tools to achieve the same result:CREATE OR REPLACE FUNCTION
pwc210.task1_plperl( int[] )
RETURNS int
AS $CODE$
my ( $list ) = @_;
my $max = 0;
my @removed;
for ( $list->@* ) {
$max = $_ if( $max < $_ );
}
for my $index ( 2 .. $max ) {
next if ( grep { $_ == $index } @removed );
next if ( grep { $_ == ( $index + 1 ) } @removed );
next if ( grep { $_ == ( $index - 1 ) } @removed );
push @removed, ( grep( { $_ == $index } $list->@* ),
grep( { $_ == ( $index + 1) } $list->@* ),
grep( { $_ == ( $index - 1) } $list->@* ) );
}
my $sum = 0;
$sum += $_ for ( @removed );
return $sum;
$CODE$
LANGUAGE plperl;
PWC 210 - Task 2 - PL/Perl Implementation
Same approach as in Raku:CREATE OR REPLACE FUNCTION
pwc210.task2_plperl( int[] )
RETURNS SETOF int
AS $CODE$
my ( $list ) = @_;
my $move = 1;
while ( $move ) {
$move = 0;
for my $index ( 0 .. scalar( $list->@* ) - 1 ) {
my $offset = $list->[ $index ] > 0 ? 1 : -1;
my ( $left, $right ) = ( $list->[ $index ], $list->[ $index + $offset ] );
next if ( ! $left || ! $right );
next if ( $left > 0 && $right > 0 );
next if ( $left < 0 && $right < 0 );
$move++;
$right *= ( $right < 0 ? -1 : 1 );
$left *= ( $left < 0 ? -1 : 1 );
$list->[ $index ] = 0 if ( $left <= $right );
$list->[ $index + $offset ] = 0 if ( $left >= $right );
}
$list = [ grep { $_ != 0 } $list->@* ];
}
for ( $list->@* ) {
next if ( ! $_ );
return_next( $_ );
}
return undef;
$CODE$
LANGUAGE plperl;
PostgreSQL Implementations
PWC 210 - Task 1 - PL/PgSQL Implementation
I cheated here: since I’m not sure I’ve understood very well the implementations, and I’m in a rush, I simply delegated to PL/Perl the implementation!CREATE OR REPLACE FUNCTION
pwc210.task1_plpgsql( l int[] )
RETURNS int
AS $CODE$
SELECT pwc210.task1_plperl( l );
$CODE$
LANGUAGE sql;
PWC 210 - Task 2 - PL/PgSQL Implementation
I cheated here: since I’m not sure I’ve understood very well the implementations, and I’m in a rush, I simply delegated to PL/Perl the implementation!CREATE OR REPLACE FUNCTION
pwc210.task2_plpgsql( l int[] )
RETURNS SETOF int
AS $CODE$
SELECT pwc210.task2_plperl( l );
$CODE$
LANGUAGE sql;