Perl Weekly Challenge 234: nested loops
This post presents my solutions to the Perl Weekly Challenge 234.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 234 - Task 1 - Raku
- PWC 234 - Task 2 - Raku
- PWC 234 - Task 1 in PostgreSQL PL/Perl
- PWC 234 - Task 2 in PostgreSQL PL/Perl
- PWC 234 - Task 1 in PostgreSQL PL/PgSQL
- PWC 234 - Task 2 in PostgreSQL PL/PgSQL
Raku Implementations
PWC 234 - Task 1 - Raku Implementation
The first task was about finding out all characters that appear in a list of words.sub MAIN( *@words ) {
my %chars;
for @words -> $current_word {
for $current_word.comb.unique.sort {
%chars{ $_ }.push: $current_word;
}
}
for %chars.kv -> $char, $list {
say $char if $list.elems == @words.elems;
}
}
I first disassemble each word, and then print out those chars that have an appearing list of words of the same size of the input.
PWC 234 - Task 2 - Raku Implementation
The second taskw as about finding a triplet of array indexes so that each number is different from the other twos. I used a nested loop do achieve the aim.sub MAIN( *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {
my @triples;
#(i, j, k) that satisfies num[i] != num[j], num[j] != num[k] and num[k] != num[i].
for 0 ..^ @nums.elems - 2 -> $i {
for $i ^..^ @nums.elems - 1 -> $j {
for $j ^..^ @nums.elems -> $k {
@triples.push: [ $i, $j, $k ] if ( @nums[ $i ] != @nums[ $j ]
&& @nums[ $j ] != @nums[ $k ]
&& @nums[ $k ] != @nums[ $i ] );
}
}
}
@triples.join( "\n" ).say;
}
PL/Perl Implementations
PWC 234 - Task 1 - PL/Perl Implementation
Similar to the Raku implementation, using an hash to keep track of the charaters andgrep
to search fo duplicated words.
CREATE OR REPLACE FUNCTION
pwc234.task1_plperl( text[] )
RETURNS SETOF char
AS $CODE$
my ( $words ) = @_;
my $chars = {};
for my $current_word ( $words->@* ) {
for my $current_char ( sort split //, $current_word ) {
if ( ! grep { $_ eq $current_word } $chars->{ $current_char }->@* ) {
push $chars->{ $current_char }->@*, $current_word;
}
}
}
for my $current_char ( keys $chars->%* ) {
return_next( $current_char ) if ( $chars->{ $current_char }->@* == scalar $words->@* );
}
return undef;
$CODE$
LANGUAGE plperl;
PWC 234 - Task 2 - PL/Perl Implementation
A nested loop over the arrays to find the triplets. Note that the function returns atable
, so an hash is returned.
CREATE OR REPLACE FUNCTION
pwc234.task2_plperl( int[] )
RETURNS TABLE( i int, j int, k int )
AS $CODE$
my ( $nums ) = @_;
for my $i ( 0 .. $nums->@* - 3 ) {
for my $j ( $i + 1 .. $nums->@* - 2 ) {
for my $k ( $j + 1 .. $nums->@* - 1 ) {
return_next( { i => $i, j => $j, k => $k } )
if ( $nums->[ $i ] != $nums->[ $j ]
&& $nums->[ $j ] != $nums->[ $k ]
&& $nums->[ $k ] != $nums->[ $i ] );
}
}
}
return undef;
$CODE$
LANGUAGE plperl;
PostgreSQL Implementations
PWC 234 - Task 1 - PL/PgSQL Implementation
This is not an optimal solution, but it is the only one that comes into my mind right now. I use a temporary table to store the chars and the words they belong to, then extract all the chars with more occurrencies than the words.CREATE OR REPLACE FUNCTION
pwc234.task1_plpgsql( words text[] )
RETURNS SETOF char
AS $CODE$
DECLARE
w text;
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS chars( c char, word text );
TRUNCATE chars;
FOREACH w IN ARRAY words LOOP
INSERT INTO chars
SELECT c, w
FROM regexp_split_to_table( w, '' ) c;
END LOOP;
RETURN QUERY
SELECT c
FROM chars
GROUP BY c
HAVING count( word ) >= array_length( words, 1 );
END
$CODE$
LANGUAGE plpgsql;
PWC 234 - Task 2 - PL/PgSQL Implementation
Nested loops, nothing to say here.CREATE OR REPLACE FUNCTION
pwc234.task2_plpgsql( nums int[] )
RETURNS TABLE (ii int, jj int, kk int )
AS $CODE$
BEGIN
FOR i IN 1 .. array_length( nums, 1 ) - 2 LOOP
FOR j IN i + 1 .. array_length( nums, 1 ) - 1 LOOP
FOR k IN j + 1 .. array_length( nums, 1 ) LOOP
IF nums[i] <> nums[j] AND nums[j] <> nums[k] AND nums[k] <> nums[i] THEN
raise info '% % %', i, j, k;
ii := i;
jj := j;
kk := k;
RETURN NEXT;
END IF;
END LOOP;
END LOOP;
END LOOP;
END
$CODE$
LANGUAGE plpgsql;