Perl Weekly Challenge 229: delete if unsorted, keep if multiple occurrencies
This post presents my solutions to the Perl Weekly Challenge 229.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 229 - Task 1 - Raku
- PWC 229 - Task 2 - Raku
- PWC 229 - Task 1 in PostgreSQL PL/Perl
- PWC 229 - Task 2 in PostgreSQL PL/Perl
- PWC 229 - Task 1 in PostgreSQL PL/PgSQL
- PWC 229 - Task 2 in PostgreSQL PL/PgSQL
Raku Implementations
PWC 229 - Task 1 - Raku Implementation
The first task was about computing how many words to delete from a given list, given that a word has to be deleted if its chars are not in order.sub MAIN( *@words is copy ) {
my $deleted = 0;
for 0 ..^ @words.elems {
my $word = @words[ $_ ];
@words[ $_ ]:delete and $deleted++ if $word ne $word.comb.sort.join;
}
$deleted.say;
}
The idea is simple: I split the word into letters, sort and rejoin. If the result is different from the original word, such word has to be deleted.
PWC 229 - Task 2 - Raku Implementation
The second task was about finding out elements replicated in at least two out of three arrays.sub MAIN() {
my @array1 = 1, 1, 2, 4;
my @array2 = 2, 4;
my @array3 = 4;
my %bag;
%bag{ $_ }++ for @array1.unique;
%bag{ $_ }++ for @array2.unique;
%bag{ $_ }++ for @array3.unique;
%bag.keys.grep( { %bag{ $_ } >= 2 } ).join( ',' ).say;
}
I use
%bag
to enumerate the values, taking care of unique
values only.
PL/Perl Implementations
PWC 229 - Task 1 - PL/Perl Implementation
Same implementation as Raku.CREATE OR REPLACE FUNCTION
pwc229.task1_plperl( text[])
RETURNS int
AS $CODE$
my ( $words ) = @_;
my $deleted = 0;
for my $word ( $words->@* ) {
my $sorted = join( '', sort( split( //, $word ) ) );
$deleted++ if ( $word ne $sorted );
}
return $deleted;
$CODE$
LANGUAGE plperl;
PWC 229 - Task 2 - PL/Perl Implementation
Same implementation as in Raku.CREATE OR REPLACE FUNCTION
pwc229.task2_plperl( int[], int[], int[] )
RETURNS SETOF int
AS $CODE$
my $bag = {};
for my $array ( @_ ) {
my $uniq = {};
for my $item ( $array->@* ) {
$uniq->{ $item }++;
$bag->{ $item }++ if ( $uniq->{ $item } == 1 );
}
}
for my $item ( keys $bag->%* ) {
return_next( $item ) if ( $bag->{ $item } >= 2 );
}
return undef;
$CODE$
LANGUAGE plperl;
Here I iterate over each incoming array, and use an utility hash
$uniq
to keep only unique values for the current array, placing them into the $bag
hash.
PostgreSQL Implementations
PWC 229 - Task 1 - PL/PgSQL Implementation
Similar to the other implementations, but this time I use a query to obtain the sorted word.CREATE OR REPLACE FUNCTION
pwc229.task1_plpgsql( words text[] )
RETURNS int
AS $CODE$
DECLARE
current_word text;
sorted_word text;
deleted int := 0;
BEGIN
FOREACH current_word IN ARRAY words LOOP
WITH letters( l ) AS (
SELECT regexp_split_to_table( current_word, '' )::text
ORDER BY 1
)
SELECT string_agg( l, '' )
INTO sorted_word
FROM letters;
IF sorted_word <> current_word THEN
deleted := deleted + 1;
END IF;
END LOOP;
RETURN deleted;
END
$CODE$
LANGUAGE plpgsql;
The
regexp_split_to_table
splits the word into a table, that is then reaggregated with string_agg
.
PWC 229 - Task 2 - PL/PgSQL Implementation
Use a temporary table to store every element of the array, grouping them and counting those with multiple occurrencies.CREATE OR REPLACE FUNCTION
pwc229.task2_plpgsql( aa int[], ab int[], ac int[] )
RETURNS SETOF INT
AS $CODE$
DECLARE
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS bag( v int, c int, a text );
TRUNCATE TABLE bag;
INSERT INTO bag( v, c, a )
SELECT v, count(*), 'a'
FROM unnest( aa ) v
GROUP BY 1,3;
INSERT INTO bag( v, c, a )
SELECT v, count(*), 'b'
FROM unnest( ab ) v
GROUP BY 1,3;
INSERT INTO bag( v, c, a )
SELECT v, count(*), 'c'
FROM unnest( ac ) v
GROUP BY 1,3;
RETURN QUERY
SELECT v
FROM bag
WHERE c = 1
GROUP by v
HAVING sum( c ) >= 2;
END
$CODE$
LANGUAGE plpgsql;