Perl Weekly Challenge 164: quick and easy

It is sad that, after more than two years of me doing Raku, I still don’t have any production code project to work on. Therefore, in order to keep my coding and Raku-ing (is that a term?) knowdledge, I try to solve every Perl Weekly Challenge tasks.

In the following, the assigned tasks for Challenge 164.

and for the sake of some Perl 5, let’s do some stuff also in PostgreSQL Pl/Perl:
Last, the solutions in PostgreSQL PL/PgSQL:

This task was about finding prime numbers less than `1000` that are palindromes too. I decided to implement it as a `lazy gather` array implementation:

``````sub MAIN( Int \$limit = 1000 ) {
my @primes-palindrome = lazy gather {
for 0 ..^ \$limit {
take \$_ if \$_.is-prime && \$_.Str.flip == \$_.Str && \$_.Str.comb.chars > 1;
}
};

.say for @primes-palindrome;
}

``````

It simply checks for a number to be prime, if its stringified representtion is equal to its flipped (i.e. reversed) repreentation, and to have at least two chars.

find the first eight happy numbers, where a number is happy if it can be reduced to `1` by summing the squares of its digits:

``````sub MAIN( Int \$limit = 8 ) {
my @happy-numbers = lazy gather {
for 10 .. Inf {
my \$sum = \$_.comb.map( * ** 2 ).sum;
while ( \$sum.comb.elems > 1 ) {
\$sum = \$sum.comb.map( * ** 2 ).sum;
}

take \$_ if \$sum == 1;
}
};

@happy-numbers[ 0 .. \$limit ].join( ', ' ).say;
}

``````

Again, I decided to implement with a `lazy gather` approach and an infinite loop. Within the loop, I reduce the number to its `\$sum`, that is the sum of the squares of its digits. I reiterate the approach while the `\$sum` has more than one digit, and when it finally has a single digit, I return the number only if it is equal to `1`.

PWC 164 - Task 1 in PostgreSQL PL/Perl

A simple implementation using two anonymous subroutines to check if a number is prime and if it is palindrome:

``````CREATE OR REPLACE FUNCTION
RETURNS SETOF int
AS \$CODE\$
my ( \$limit ) = @_;

my \$is_prime = sub {
my ( \$number ) = @_;
for my \$i ( 2 .. \$number - 1 ) {
return 0 if \$number % \$i == 0;
}

return 1;
};

my \$is_palindrome = sub {
return \$_[ 0 ] eq reverse \$_[ 0 ];
};

for  ( 10 .. \$limit ) {
return_next( \$_ ) if \$is_prime->( \$_ ) && \$is_palindrome->( \$_ );
}

return undef;
\$CODE\$
LANGUAGE plperl;
``````

The function returns a new number when found using `return_next`.

PWC 164 - Task 2 in PostgreSQL Pl/Perl

I created an anonymous subroutine that, given a number, reduces it to a single digit and provides a boolean value if the number is happy. Than it is a matter of looping before returning a new number:

``````CREATE OR REPLACE FUNCTION
RETURNS SETOF int
AS \$CODE\$
my ( \$limit ) = @_;

my \$is_happy = sub {
my ( \$num ) = @_;
my \$sum = \$num;
while ( \$num > 10 ) {
\$sum = 0;
\$sum += \$_ for map { \$_ ** 2 }  split( //, \$num );
\$num = \$sum;
\$sum = 0;
}

return \$num == 1;
};

for ( 10 .. 99999 ) {
\$limit-- and return_next( \$_ )  if \$is_happy->( \$_ );
last if \$limit == 0;
}

return undef;
\$CODE\$
LANGUAGE plperl;

``````

It is interesting to note that I do loop until `\$limit` reaches zero, and `\$limit` is decreased before `return_next` is executed thanks to the low priority `and`.

PWC 164 - Task 1 in PostgreSQL Pl/PgSQL

Same implementation as PL/Perl, but this time the function to understand if a number is prime is a separate one:

``````CREATE OR REPLACE FUNCTION
pwc164.is_prime( n int )
RETURNS boolean
AS \$CODE\$
DECLARE
BEGIN
FOR i IN 2 .. n - 1 LOOP
IF n % i = 0 THEN
RETURN false;
END IF;
END LOOP;

RETURN true;
END
\$CODE\$
LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION
pwc164.task1_plpgsql( l int DEFAULT 1000 )
RETURNS SETOF INT
AS \$CODE\$
DECLARE
BEGIN

FOR n IN 10 .. l LOOP
IF pwc164.is_prime( n ) AND n = reverse( n::text )::int THEN
RETURN NEXT n;
l := l - 1;
END IF;

EXIT WHEN l = 0;
END LOOP;

RETURN;
END
\$CODE\$
LANGUAGE plpgsql;
``````

Luckily, there is a built-in `reverse` function that can be used to check if the number, converted to a string, is equal to the starting number.

PWC 164 - Task 2 in PostgreSQL Pl/PgSQL

Same implementation as PL/Perl, but with a standalone function to check if the number is happy:

``````CREATE OR REPLACE FUNCTION
pwc164.is_happy( n int )
RETURNS bool
AS \$CODE\$
DECLARE
s  int;
nn int;
BEGIN
WHILE n > 10 LOOP
s := 0;
FOREACH nn IN ARRAY regexp_split_to_array( n::text, '' )::int[] LOOP
s := s + nn * nn;
END LOOP;

n := s;

END LOOP;

IF n = 1 THEN
RETURN true;
ELSE
RETURN false;
END IF;
END
\$CODE\$
LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION
pwc164.task2_plpgsql( l int DEFAULT 8 )
RETURNS SETOF INT
AS \$CODE\$
DECLARE
BEGIN
FOR n IN 10 .. 99999 LOOP
IF pwc164.is_happy( n ) THEN
RETURN NEXT n;
l := l - 1;
END IF;

EXIT WHEN l = 0;
END LOOP;

RETURN;
END
\$CODE\$
LANGUAGE plpgsql;

``````

I use a `regexp_split_to_array()` call to get all the digits of the number to check, than I iterate on every digit and do the sum `s`. I repeat the same workflow until the number has a single digit, in such case I can test for its happyness.
The other function simply represents the entry point and does the looping, then returning every happy number found.

The article Perl Weekly Challenge 164: quick and easy has been posted by Luca Ferrari on May 9, 2022