Perl Weekly Challenge 176: scrumbled numbers

It is sad that, after more than three 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 176.

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:

PWC 176 - Task 1

Find the first and lowest integer number so that the equivalent numbers multiplied by a factor ranging from 2 to 6 are composed by the very same digits. The idea is quite simple:
  • grab a number;
  • compute the multiplied @values;
  • compute the @permutations of the original number and make them integers;
  • see if the number of $found permutations that are in the @values multiplied is the right number.


sub MAIN() {

    for 1 .. Inf -> $current {
        my @values = (1 .. 6).map: { $current * $_ };
        # compute the permutations of the current number
        my @permutations = $current.comb.permutations.map: *.join.Int;

        my $found = 0;
        for @values {
            $found++ if $_ == any(@permutations);
        }

        $current.say and last if $found == @values.elems;
    }
}



PWC 176 - Task 2

Find out all reversable numbers up to 100: a number that summed with its mirrored version provides a value made only by odd digits. Quite simple to implement:

sub MAIN( Int $limit = 100 ) {

    for 1 .. $limit {
        $_.say if ! ( $_ + $_.flip.Int ).comb.grep( * %% 2 );
    }
}



But my first implementation was wrong: I used reverse instead of flip, so I got more numbers than those I was expected to get!

PWC 176 - Task 1 in PostgreSQL PL/Perl

The same Raku solution, with a little more work due to chaining split (to get the digits), sort and join:

CREATE OR REPLACE FUNCTION
pwc176.task1_plperl()
RETURNS BIGINT
AS $CODE$

for my $current ( 1 .. 999999 ) {

    my @values = map { $_ * $current } ( 2 .. 6 );

    my $found = 1;
    for ( @values ) {
        my $sorted_digits = join( '', sort( split( '', $current ) ) );
        my $other_digits  = join( '', sort( split( '', $_ ) ) );

        $found = 0 if ( $sorted_digits != $other_digits );
        last if ! $found;
    }

    next if ! $found;
    return $current;
}

$CODE$
LANGUAGE plperl;



The idea is the same: I do map the original number multiplying it by a factor, then use split to get the digits, sort to place them in the same order, and join to make it a number again. If two numbers undergoing this chain of methods result in the same value, it means they have the same digits!

PWC 176 - Task 2 in PostgreSQL PL/Perl

The idea is similar to the Raku implementation, with some extra work due to method chaining:

CREATE OR REPLACE FUNCTION
pwc176.task2_plperl( int )
RETURNS SETOF INT
AS $CODE$

my ( $limit ) = @_;
$limit //= 100;

for my $current ( 1 .. $limit ) {
    my $sum = $current + reverse( $current );
    my @digits = split( '', $sum );
    return_next( $current ) if ( ! grep( { $_ % 2 == 0 } @digits ) );
}

return undef;


$CODE$



PWC 176 - Task 1 in PostgreSQL PL/PgSQL

In the beginning I thought about simply calling the PL/Perl implementation, than I implemented it with a pure PL/PgSQL function:

CREATE OR REPLACE FUNCTION
pwc176.task1_plpgsql()
RETURNS BIGINT
AS $CODE$
DECLARE
        i int;
        m int;
        v int;
        c int;
BEGIN
<<main_loop>>
     FOR i IN 1 .. 999999 LOOP
         FOR m IN 2 .. 6 LOOP
             v := m * i;
             c := 0;

             SELECT count( vv )
             INTO c
             FROM regexp_split_to_table( v::text, '' ) vv
             WHERE vv NOT IN ( SELECT * FROM regexp_split_to_table( i::text, '') );

             CONTINUE main_loop WHEN c <> 0;
         END LOOP;

         -- if here, ok!
         RETURN i;
     END LOOP;
END
$CODE$
LANGUAGE plpgsql;



For any given number i I do compute its multiplication by a factor m and store it into v. Then I execute a query to see if all digits (via regexp_split_to_table()) of v are within the digits of i: I do count and place into c the number of digits that do not correspond. Therefore, if c is not zero, the current number has a multiple that has not the same digits, so I can restart (or continue) the loop with a next i.

PWC 176 - Task 2 in PostgreSQL PL/PgSQL

Simple enough to be implemented with a check done by a query: for a given number i I do compute the sum with its mirrored part and count how many even digits are there in the resulting sum. If the count is not zero, the number is not reversable, otherwise I can return it within the result set.

CREATE OR REPLACE FUNCTION
pwc176.task2_plpgsql( l int default 100 )
RETURNS SETOF INT
AS $CODE$
DECLARE
        i int;
        s int;
        c int;
BEGIN

        FOR i IN 1 .. l LOOP
            s := i + reverse( i::text )::int;
            c := 0;

            SELECT count( v )
            INTO c
            FROM regexp_split_to_table( s::text, '' ) v
            WHERE v::int % 2 = 0;

            IF c = 0 THEN
               RETURN NEXT i;
            END IF;
        END LOOP;

RETURN;
END
$CODE$
LANGUAGE plpgsql;



The article Perl Weekly Challenge 176: scrumbled numbers has been posted by Luca Ferrari on August 2, 2022