Perl Weekly Challenge 235: integer arrays
This post presents my solutions to the Perl Weekly Challenge 235.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 235 - Task 1 - Raku
- PWC 235 - Task 2 - Raku
- PWC 235 - Task 1 in PostgreSQL PL/Perl
- PWC 235 - Task 2 in PostgreSQL PL/Perl
- PWC 235 - Task 1 in PostgreSQL PL/PgSQL
- PWC 235 - Task 2 in PostgreSQL PL/PgSQL
Raku Implementations
PWC 235 - Task 1 - Raku Implementation
The first task was about discovering if a given input array of integers is naturally sorted removing only one item.sub MAIN( *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {
for 0 ..^ @nums.elems {
my @current;
@current.push: | @nums[ 0 .. $_ - 1 ] if $_ != 0;
@current.push: | @nums[ $_ + 1 ..^ @nums.elems ];
'true'.say and exit if @current ~~ @current.sort;
}
'false'.say;
}
I build at every step an array made by a slice of the original array, and compare it with its sorted version. If both the array are the same, the result is
true
.
PWC 235 - Task 2 - Raku Implementation
The second task was about duplicating every0
found in a given array of integers, without exceeding the array size, that means trailing the extra digits.
sub MAIN( *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {
my @result;
for 0 ..^ @nums.elems {
# add the leading zero
@result.push: 0 if @nums[ $_ ] == 0;
# add the number, even if it is a zero, duplicated
# from the row above
@result.push: @nums[ $_ ];
}
@result[ 0 ..^ @nums.elems ].join( ',' ).say;
}
I add every digit to the
@result
array, and add it twice if it is a zero. In the end, I output only the slice of the array.
PL/Perl Implementations
PWC 235 - Task 1 - PL/Perl Implementation
A bit by bit similar solution to the Raku one.CREATE OR REPLACE FUNCTION
pwc235.task1_plperl( int[] )
RETURNS boolean
AS $CODE$
my ( $nums ) = @_;
for ( 0 .. $nums->@* - 1 ) {
my @current;
push @current, $nums->@[ 0 .. $_ - 1 ] if ( $_ != 0 );
push @current, $nums->@[ $_ + 1 .. $nums->@* - 1 ];
return 1 if ( join( ',', @current ) eq join( ',', sort @current ) );
}
return 0;
$CODE$
LANGUAGE plperl;
This time, I compare the stringified version of the array and of the sorted one to see it if matches.
PWC 235 - Task 2 - PL/Perl Implementation
This time I return every digit when I encounter it, stopping when the max size is found.CREATE OR REPLACE FUNCTION
pwc235.task2_plperl( int[] )
RETURNS SETOF int
AS $CODE$
my ( $nums ) = @_;
my $remaining = $nums->@* - 1;
for ( $nums->@* ) {
return_next( $_ );
$remaining--;
return undef if $remaining <= 0;
return_next( 0 ) if ( $_ == 0 );
$remaining--;
return undef if $remaining <= 0;
}
return undef;
$CODE$
LANGUAGE plperl;
PostgreSQL Implementations
PWC 235 - Task 1 - PL/PgSQL Implementation
A quite verbose solution, but nothing better came into my mind.CREATE OR REPLACE FUNCTION
pwc235.task1_plpgsql( nums int[] )
RETURNS boolean
AS $CODE$
DECLARE
current_array int[];
string_array text;
string_sorted text;
BEGIN
SELECT string_agg( x::text, ',' )
INTO string_array
FROM ( SELECT unnest( nums ) y ORDER BY 1 ) x
ORDER BY 1;
FOR i IN 1 .. array_length( nums, 1 ) LOOP
current_array := '{}';
IF i <> 1 THEN
current_array := current_array || nums[ 1 : ( i - 1 ) ];
END IF;
current_array := current_array || nums[ ( i + 1 ) : ];
SELECT string_agg( x::text, ',' )
INTO string_sorted
FROM ( SELECT y::text FROM unnest( current_array ) y ORDER BY 1 ) x
;
SELECT string_agg( x::text, ',' )
INTO string_array
FROM ( SELECT y::text FROM unnest( current_array ) y ) x
;
IF string_sorted = string_array THEN
RETURN true;
END IF;
END LOOP;
RETURN false;
END
$CODE$
LANGUAGE plpgsql;
The idea is to slice the original array into one that has all elements except one. Then I build a string representation of the built array and of the sorted one, and if the strings are the same, I can stop.
PWC 235 - Task 2 - PL/PgSQL Implementation
Simple solution using the same PL/Perl approach: return every digit, return a zero twice, stop as soon as the max size is reached.CREATE OR REPLACE FUNCTION
pwc235.task2_plpgsql( nums int[] )
RETURNS SETOF int
AS $CODE$
DECLARE
current_element int;
remaining int;
BEGIN
remaining := array_length( nums, 1 );
FOREACH current_element IN ARRAY nums LOOP
RETURN NEXT current_element;
remaining := remaining - 1;
IF remaining = 0 THEN
RETURN;
END IF;
IF current_element = 0 THEN
RETURN NEXT 0;
remaining := remaining - 1;
END IF;
IF remaining = 0 THEN
RETURN;
END IF;
END LOOP;
RETURN;
END
$CODE$
LANGUAGE plpgsql;