Perl Weekly Challenge 241: loops everywhere!

This post presents my solutions to the Perl Weekly Challenge 241.
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:
The PL/Perl implementations are very similar to a pure Perl implementation, even if the PostgreSQL environment could involve some more constraints. Similarly, the PL/PgSQL implementations help me keeping my PostgreSQL programming skills in good shape.

Raku Implementations

PWC 241 - Task 1 - Raku Implementation

The first task was about finding a triplet in an already sorted array where the difference between couple of values is the searched for value. I implemented this with a straighforward nested triple nested loop.

sub MAIN( Int :$diff
	  , Bool :$verbose = True
	  , *@nums where { @nums.grep( * ~~ Int ).Array.elems == @nums.elems }
	) {

    my @triplets;
    # a) i < j < k
    # b) nums[j] - nums[i] == diff
    # c) nums[k] - nums[j] == diff
    for 0 ..^ @nums.elems -> $i {
		for $i ^..^ @nums.elems -> $j {
		    for $j ^..^ @nums.elems -> $k {
				@triplets.push: [ @nums[ $k, $j, $i ] ] if ( ( @nums[ $j ] - @nums[ $i ] ) == ( @nums[ $k ] - @nums[ $j ] )
									   && ( @nums[ $k ] - @nums[ $j ] ) == $diff );
			    }
		}
    }


    @triplets.elems.say;
    @triplets.join( "\n" ).say;

}



PWC 241 - Task 2 - Raku Implementation

The second task was about sorting input numbers by the count of their prime factors. I needed an helper function to compute the list of prime factors, then I stored every number into an hash keyed by the count of the prime factor list, so that sorting the hash by key gives me back the sorted values.

sub prime_factors (Int $n) {
    return $n if $n <= 1;
    my $residue = $n;
    my @factors;

    for 2 .. $n {
	while ( $residue %% $_ ) {
	    @factors.push: $_;
	    $residue /= $_;
	}

	last if $residue == 1;
    }

    return @factors;
}

sub MAIN( *@nums where { @nums.grep( * ~~Int ).elems == @nums.elems } ) {
    my %sorted;
    for @nums {
	%sorted{ prime_factors( $_.Int ).elems }.push: $_;
    }

    %sorted{ $_ }.join( "," ).say for  %sorted.keys.sort;
}



PL/Perl Implementations

PWC 241 - Task 1 - PL/Perl Implementation

The same implementation already exolained, with a triple nested loop.

CREATE OR REPLACE FUNCTION
pwc241.task1_plperl( int[], int )
RETURNS int
AS $CODE$
   my ( $nums, $diff ) = @_;
   my @triplets;

   for my $i ( 0 .. $nums->@* - 1) {
       for my $j ( $i + 1 .. $nums->@* - 1) {
       	   for my $k ( $j + 1 .. $nums->@* - 1) {
	       if ( ( $nums->[ $k ] - $nums->[ $j ] ) == ( $nums->[ $j ] - $nums->[ $i ] )
	       	  && ( $nums->[ $k ] - $nums->[ $j ] ) == $diff ) {
		  push @triplets, [ $nums->[ $k ], $nums->[ $j ], $nums->[ $i ] ];
	      }
	   }
       }
   }

   return scalar @triplets;
$CODE$
LANGUAGE plperl;



PWC 241 - Task 2 - PL/Perl Implementation

Same implementation as Raku, but this time I use an inner function to get the primes.

CREATE OR REPLACE FUNCTION
pwc241.task2_plperl( int[] )
RETURNS SETOF int
AS $CODE$
   my ( $nums ) = @_;

   my $factors = sub {
      my ( $n ) = @_;
      my $primes = [];

      for ( 2 .. $n ) {
      	  while ( $n % $_ == 0 ) {
	  	push $primes->@*, $_;
		$n /= $_;
	  }

	  last if $n == 1;
      }

      return $primes;
   };

   my $sorted = {};
   push $sorted->{ scalar( $factors->( $_ )->@* ) }->@*, $_ for ( $nums->@* );

   for my $key ( sort keys $sorted->%* ) {
       return_next( $_ ) for ( $sorted->{ $key }->@* );
   }

return undef;
$CODE$
LANGUAGE plperl;



PostgreSQL Implementations

PWC 241 - Task 1 - PL/PgSQL Implementation

Same triple nested loop as per other implementations:

CREATE OR REPLACE FUNCTION
pwc241.task1_plpgsql( nums int[], diff int )
RETURNS int
AS $CODE$
DECLARE
	counter int := 0;
BEGIN
	FOR i IN 1 .. array_length( nums, 1 ) LOOP
	    FOR j IN ( i + 1 ) .. array_length( nums, 1 ) LOOP
	    	FOR k IN ( j + 1 ) .. array_length( nums, 1 ) LOOP
		    IF ( nums[ k ] - nums[ j ] ) = ( nums[ j ] - nums[ i ] ) AND ( nums[ k ] - nums[ j ] = diff ) THEN
		       counter := counter + 1;
		    END IF;
		END LOOP;
	    END LOOP;
	END LOOP;

	RETURN counter;
END
$CODE$
LANGUAGE plpgsql;



PWC 241 - Task 2 - PL/PgSQL Implementation

This time I use a temporary table to store the number and its prime factor counting. Then I query the table to get the values sorted by the counting of the primes.

CREATE OR REPLACE FUNCTION
pwc241.primes( n int )
RETURNS SETOF int
AS $CODE$
BEGIN
	FOR i IN 2 .. n LOOP
	    WHILE ( n % i ) = 0 LOOP
	    	  RETURN NEXT i;
		  n := n / i;
	    END LOOP;


	    IF n = 1 THEN
	       RETURN;
	    END IF;
	END LOOP;

RETURN;
END
$CODE$
LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION
pwc241.task2_plpgsql( nums int[] )
RETURNS SETOF int
AS $CODE$
DECLARE
	v int;
BEGIN
	CREATE TEMPORARY TABLE IF NOT EXISTS sorted( n int, p int DEFAULT 0 );
	TRUNCATE sorted;

	FOREACH v IN ARRAY nums LOOP
		INSERT INTO sorted( n, p )
		SELECT v, pp
		FROM pwc241.primes( v ) pp;
	END LOOP;

	RETURN QUERY
	       WITH q( n ) AS ( SELECT n FROM sorted ORDER BY p asc )
	       SELECT distinct n
	       FROM Q qq;


END
$CODE$
LANGUAGE plpgsql;



Python Implementations

PWC 241 - Task 1 - Python Implementation

Again, a triple nested loop implementation. Note however, how it is required to transform the values into integers.

import sys

# task implementation
def main( argv ):
    diff = int(argv[ 0 ])
    nums = list( map( int, argv[ 1: ] ) )
    counter = 0

    for i in range( 0, len( nums ) ):
        for j in range( i + 1, len( nums ) ):
            for k in range( j + 1, len( nums ) ):
               if ( ( nums[ k ] - nums[ j ] ) == ( nums[ j ] - nums[ i ] ) and ( nums[ k ] - nums[ j ] ) == diff ):
                   counter += 1

    print( counter )
    return counter



# invoke the main without the command itself
if __name__ == '__main__':
    main( sys.argv[ 1: ] )





PWC 241 - Task 2 - Python Implementation

The same implementation used for the other Raku and Perl implementation: a dictionary stores the values keyed by the counting of the prime factors.

import sys

def get_primes( n ):
    primes = []
    for i in range(2, n):
        while n % i == 0:
            primes.append( i )
            n /= i

        if n == 1:
            break

    return primes

# task implementation
def main( argv ):
    sorted_dict = {}
    for current in argv:
        counter = len( get_primes( int( current ) ) )
        if not counter in sorted_dict:
            sorted_dict[ counter ] = []

        sorted_dict[ counter ].append( current )

    for key in sorted( sorted_dict ):
        for v in sorted_dict[ key ]:
            print( v )


# invoke the main without the command itself
if __name__ == '__main__':
    main( sys.argv[ 1: ] )





The article Perl Weekly Challenge 241: loops everywhere! has been posted by Luca Ferrari on October 30, 2023