Perl Weekly Challenge 262: another short one!
This post presents my solutions to the Perl Weekly Challenge 262.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 262 - Task 1 - Raku
- PWC 262 - Task 2 - Raku
- PWC 262 - Task 1 in PostgreSQL PL/Perl
- PWC 262 - Task 2 in PostgreSQL PL/Perl
- PWC 262 - Task 1 in PostgreSQL PL/PgSQL
- PWC 262 - Task 2 in PostgreSQL PL/PgSQL
- PWC 262 - Task 1 in PL/Java
- PWC 262 - Task 2 in PL/Java
- PWC 262 - Task 1 in Python
- PWC 262 - Task 2 in Python
Raku Implementations
PWC 262 - Task 1 - Raku Implementation
The first task was about computing the max counting among positive and negative integers.sub MAIN( *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {
    ( @nums.grep( * >= 0 ).elems, @nums.grep( * < 0 ).elems ).max.say;
}
PWC 262 - Task 2 - Raku Implementation
The second task was to compute how many pairs of numbers are in a given array so that one is leftmost of the other, and the indexes of their positions multiplied together are a multiple of a given valuek.
sub MAIN( Int $k where { $k != 0 },
	  *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {
    my @pairs;
    for 0 ..^ @nums.elems -> $i {
		for $i ^..^ @nums.elems -> $j {
		    next if ( $i * $j ) !%% $k;
		    next if @nums[ $i ] != @nums[ $j ];
		    @pairs.push: [ $i, $j ];
		}
    }
    @pairs.elems.say;
}
PL/Perl Implementations
PWC 262 - Task 1 - PL/Perl Implementation
A very simple implementation using againgrep.
CREATE OR REPLACE FUNCTION
pwc262.task1_plperl( int[] )
RETURNS int
AS $CODE$
   my ( $nums ) = @_;
  my ( $positives, $negatives ) =
    ( scalar( grep { $_ >= 0 } $nums->@* ),
      scalar( grep { $_ < 0 } $nums->@* ) );
  return $positives >= $negatives
  	   ? $positives
	   :  $negatives;
$CODE$
LANGUAGE plperl;
PWC 262 - Task 2 - PL/Perl Implementation
A nested loop to solve the trick.CREATE OR REPLACE FUNCTION
pwc262.task2_plperl( int, int[] )
RETURNS int
AS $CODE$
   my ( $k, $nums ) = @_;
   my @pairs;
   for my $i ( 0 .. $nums->@* - 1 ) {
       for my $j ( $i + 1 .. $nums->@* - 1 ) {
       	   next if ( $i * $j ) % $k != 0;
		   next if ( $nums->@[ $i ] != $nums->@[ $j ] );
		   push @pairs, [ $i, $k ];
       }
   }
   return scalar @pairs;
$CODE$
LANGUAGE plperl;
PostgreSQL Implementations
PWC 262 - Task 1 - PL/PgSQL Implementation
A single query with a few subqueries to compute the max value.CREATE OR REPLACE FUNCTION
pwc262.task1_plpgsql( nums int[] )
RETURNS int
AS $CODE$
   WITH positives AS (
   	SELECT count( v ) as c
	FROM unnest( nums ) v
	WHERE  v >= 0
	), negatives AS (
	SELECT count( v ) as c
	FROM unnest( nums ) v
	WHERE  v < 0
	)
	, b AS (
	  SELECT c as v FROM positives
	  UNION
	  SELECT c as v FROM negatives
	  )
   SELECT max( b.v )
   FROM b;
$CODE$
LANGUAGE sql;
PWC 262 - Task 2 - PL/PgSQL Implementation
A nested loop to count the pairs. Please note that in SQL the indexes starts from1, so the same input does not provide the same result as in other languages.
CREATE OR REPLACE FUNCTION
pwc262.task2_plpgsql( k int, nums int[] )
RETURNS int
AS $CODE$
DECLARE
	pairs_count int := 0;
BEGIN
	FOR i IN 1 .. array_length( nums, 1 )  LOOP
	    FOR j IN ( i + 1 ) .. array_length( nums, 1 )  LOOP
	    	IF nums[ i ] <> nums[ j ] THEN
		   CONTINUE;
		END IF;
		IF mod( i * j, k ) <> 0 THEN
		   CONTINUE;
		END IF;
		pairs_count := pairs_count + 1;
	    END LOOP;
	END LOOP;
	RETURN pairs_count;
END
$CODE$
LANGUAGE plpgsql;
Java Implementations
PWC 262 - Task 1 - PostgreSQL PL/Java Implementation
Very simple implementation with a single loop that counts the values depending on their “type”.public class Task1 {
    private final static Logger logger = Logger.getAnonymousLogger();
    @Function( schema = "pwc262",
	       onNullInput = RETURNS_NULL,
	       effects = IMMUTABLE )
    public static final int task1_pljava( int[] nums ) throws SQLException {
		logger.log( Level.INFO, "Entering pwc262.task1_pljava" );
		int positives = 0;
		int negatives = 0;
		for ( int current : nums )
		    if ( current >= 0 )
				positives++;
		    else
				negatives++;
		return positives >= negatives ? positives : negatives;
    }
}
This can be solved also using streams, for example:
    public static final int task1_pljava( int[] nums ) throws SQLException {
		final int[] results = new int[]{ 0, 0 };
		Arrays.stream( nums )
		    .forEach( current -> {
			    int index = current >= 0 ? 0 : 1;
			    results[ index ]++;
			} );
		return results[ 0 ] >= results[ 1 ] ? results[ 0 ] : results[ 1 ];
    }
The idea is:
- convert the numsarray to a stream usingArrays.stream
- forEachvalue, placed into- currentI check if the value is positive or not, and extract an- index, either zero or one
- increment the location of resultsaccordingly, withresults[ 0 ]that represents the positive values andresults[ 1 ]that represents negative values.
PWC 262 - Task 2 - PostgreSQL PL/Java Implementation
A nested loop even in this implementation.public class Task2 {
    private final static Logger logger = Logger.getAnonymousLogger();
    @Function( schema = "pwc262",
	       onNullInput = RETURNS_NULL,
	       effects = IMMUTABLE )
    public static final int task2_pljava( int k, int[] nums ) throws SQLException {
		logger.log( Level.INFO, "Entering pwc262.task2_pljava" );
		int pairs = 0;
		for ( int i = 0; i < nums.length; i++ )
		    for ( int j = i + 1; j < nums.length; j++ )
				if ( nums[ i ] != nums[ j ]
				     || ( i * j ) % k != 0 )
				    continue;
				else
				    pairs++;
		return pairs;
    }
}
It is possible to implement this with stream, for example:
public class Task2 {
    private final static Logger logger = Logger.getAnonymousLogger();
    @Function( schema = "pwc262",
	       onNullInput = RETURNS_NULL,
	       effects = IMMUTABLE )
    public static final int task2_pljava( final int k, final int[] nums ) throws SQLException {
		final int pairs[] = new int[]{ 0 };
		IntStream.range( 0, nums.length )
		    .forEach( i -> {
			    IntStream.range( i + 1, nums.length )
				.forEach( j -> {
					if ( nums[ i ] == nums[ j ]
					     && ( i * j ) % k == 0 )
					    pairs[ 0 ]++;
				    } );
			} );
		return pairs[ 0 ];
    }
}
The idea is as follows:
- the pairsarray is a monodimensional array used only to access a counter from within the streams;
- the outer IntStream.rangeloops on theivariable, andforEachvalue opens another stream;
- the inner IntStream.rangeloops over thei+1value onjandforEachvalue tests if the array values are the same and satisfy the aim of the task
- if the current pair is fine, the counter is incremented.
Python Implementations
PWC 262 - Task 1 - Python Implementation
Same approach used in Java here: counting two types of values, but this time with afilter (like grep in Perl).
import sys
# task implementation
# the return value will be printed
def task_1( args ):
    nums = list( map( int, args ) )
    positives = len( list( filter( lambda x: True if x >= 0 else False, nums ) ) )
    negatives = len( list( filter( lambda x: True if x < 0  else False, nums ) ) )
    return positives if positives >= negatives else negatives
# invoke the main without the command itself
if __name__ == '__main__':
    print( task_1( sys.argv[ 1: ] ) )
PWC 262 - Task 2 - Python Implementation
A nested loop.import sys
# task implementation
# the return value will be printed
def task_2( args ):
    k     = int( args[ 0 ] )
    nums  = list( map( int, args[ 1: ] ) )
    pairs = []
    for i in range( 0, len( nums ) ):
        for j in range( i + 1, len( nums ) ):
            if nums[ i ] != nums[ j ] or ( i * j ) % k != 0:
                continue
            else:
                pairs.append( [ i, j ] )
    return len( pairs )
# invoke the main without the command itself
if __name__ == '__main__':
    print( task_2( sys.argv[ 1: ] ) )