Perl Weekly Challenge 137: palindrome sums on long years
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 137.
And this week, as for the previous PWC, I had time to quickly implement the tasks also on PostgreSQL
plpgsql
language:
PWC 137 - Task 1
The first task was about finding out if a given year is a long year, meaning an year with 53 weeks instead of the “ordinary” 52. This is a piece of cake using theDate
builtin class and its week-number
method:
sub MAIN() {
for 1900 .. 2100 -> $year {
$year.say if Date.new( '%04d-12-31'.sprintf( $year ) ).week-number == 53;
}
}
It could have also been written in a single line, using the postfix
for
, but the idea remains the same: iterate on every year, build a Date
object for the last day of the year, and get the week number via the week-number
method.
PWC 137 - Task 2
In this task, given an integer value greater than19
(that means, with at least two digits), we need to see if it is a Lychrel number. The idea is that, given a number, you keep adding it with its palindrome and see if the result is palindrome too. If it is, stop, the number is a Lychrel one, otherwise sum the result to its palindrome and go further.
sub MAIN( Int $n where { 10 <= $n <= 10000 }, Bool :$verbose = False ) {
my ( $result, $iteration ) = $n,0;
while ( $result < 10_000_000 && $iteration < 500 ) {
$iteration++;
$result += $result.split( '' ).reverse.join;
if $result == $result.split( '' ).reverse.join {
'0'.say;
"Found $result after $iteration iterations".say if $verbose;
exit;
}
}
'1'.say;
"Cannot find Lychrel number for $n".say if $verbose;
}
The
$result
contains the result of summing a number with its palindrome at every step. To get quickly the palindrome of a number I do use split
to get its digits, reverse
to reverse the array, and join
to re-assemble it. It is not the only way, it can be used also flip
on a Str
, or other techniques.
The
$verbose
flag allows for printing of some messages about the sattus of the computations.
PWC 137 - Task 1 in PostgreSQL plpgsql
The implementation in plpgsql
is a mirror of the implementation in Raku:
CREATE OR REPLACE FUNCTION
f_long_year()
RETURNS SETOF int
AS $CODE$
DECLARE
current_year int;
BEGIN
FOR current_year IN 1900 .. 2100 LOOP
IF date_part( 'week', make_Date( current_year, 12, 31 ) ) = 53 THEN
RETURN NEXT current_year;
END IF;
END LOOP;
RETURN;
END
$CODE$
LANGUAGE plpgsql;
The trick here is to use
date_part
, that is a magical function that allows for extracting different information from a date. The date is built with make_date
, that accepts the year, the month and the day. It is not mandatory, since a string concation is interpreted in the right sense in PostgreSQL, but using make_date
makes the function easier to red.
It is also important to note that the
for
loop does a RETURN NEXT
, that is kind of yeld: it allows the function to append a new value to the result set and proceed further with the looping. This allows the client to get results as a stream and the function to not store all of them while performing the computation.
PWC 137 - Task 2 in PostgreSQL plpgsql
The second task is a plpgsql
re-implementation of the Raku solution.
CREATE OR REPLACE FUNCTION
f_lychrel( n int, verb boolean default false )
RETURNS smallint
AS $CODE$
DECLARE
result bigint := n;
iteration int := 0;
BEGIN
IF n < 10 OR n > 10000 THEN
RAISE 'n is out of bounds!';
END IF;
WHILE result < 10000000 AND iteration < 500 LOOP
iteration = iteration + 1;
result = result + reverse( result::text )::int;
IF result = reverse( result::text )::int THEN
IF verb THEN
RAISE INFO 'Found % after % iterations', result, iteration;
END IF;
RETURN 0;
END IF;
END LOOP;
RETURN 1;
END
$CODE$
LANGUAGE plpgsql;
In the case of
plpgsql
we can exploit the reverse
function that does the flipping of a given number, converted as a text
(i.e., a string) and then reconvert the result as a number.
It is interesting to note how the
plpgsql
becomes quickly longer than the Raku implementation, and this is due to the syntax of conditionals but also to the fact that we need to check arguments within the core of the function, instead of being able to declare complex conditions on the argument list.