Perl Weekly Challenge 271: Riff Raff (i.e., the first PWC after the AC/DC live concert!)

This post presents my solutions to the Perl Weekly Challenge 271.
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 271 - Task 1 - Raku Implementation

The first task was to find the lowest index row in a binary matrix that contains the max number of 1.

usub MAIN() {

    my $matrix = [ [0, 0],
                   [1, 1],
                   [0, 0],
                 ];

    my $row = 1;
    $matrix.map( { [ $row++, $_.grep( * ~~ 1 ).elems  ] } ).grep( { $_[ 1 ] > 0 } ).map( { $_[0] } ).min.say;
}



I first map the $matrix to create an array where the first element is the $row number, and the second is the counting of 1. The result is then grep-ped to find only rows that have 1, and remapped to a list of number of row (indexes), extract the min and print out.

PWC 271 - Task 2 - Raku Implementation

The second task is about to sort an array of integers by means of the number of 1 in the binary representation of the number itself.

sub MAIN( *@nums where { @nums.elems == @nums.grep( * ~~ Int ).elems } ) {
    my %bits;
    # convert numbers into an hash keyed by the binary representation
    %bits{ $_.base( 2 ).comb.grep( * ~~ 1 ).elems }.push: $_ for @nums;

    my @output;
    @output.push: |%bits{ $_ }.sort for %bits.keys.sort;
    @output.say;
}



I build an %bits hash that is keyed by the counting of the 1 in the binary representation of the number itself, and that contains arrays of integer values. Then I build a flat list @output using the sorted keys and the values, and print it.

PL/Perl Implementations

PWC 271 - Task 1 - PL/Perl Implementation

Implementation conceptually similar to the Raku one.

CREATE OR REPLACE FUNCTION
pwc271.task1_plperl( int[][] )
RETURNS int
AS $CODE$

   my ( $matrix ) = @_;
   my $row = 1;

   my @ones =
	   map { $_->[ 0 ] }
	   grep { $_->[ 1 ] > 0 }
	   map { [ $row++,
	           scalar grep { $_ == 1 } $_->@*  # columns
		 ] } $matrix->@*; # rows

   my $min = sub {
      my $min = undef;
      for ( @_ ) {
      	  $min = $_ if ( ! $min || $min > $_ );
      }

      return $min;
   };

   return $min->( @ones );

$CODE$
LANGUAGE plperl;



The @ones array is built on a complex chain of map, grep and array dereferencing. The $min inner function is used to compute the min value.

PWC 271 - Task 2 - PL/Perl Implementation

Implementation that mimics the Raku one.

CREATE OR REPLACE FUNCTION
pwc271.task2_plperl( int[] )
RETURNS SETOF int
AS $CODE$

   my ( $nums ) = @_;


   my $binary = {};

   for ( $nums->@* ) {
       my $ones = scalar
       	  	grep { $_ eq '1' }
		split //, sprintf( "%b", $_ );
       push $binary->{ $ones }->@* , $_;
   }

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

   return undef;

$CODE$
LANGUAGE plperl;



PostgreSQL Implementations

PWC 271 - Task 1 - PL/PgSQL Implementation

This implementation uses a nested loop to traverse the matrix.

CREATE OR REPLACE FUNCTION
pwc271.task1_plpgsql( matrix int[][] )
RETURNS int
AS $CODE$
DECLARE

	counting int := 0;
BEGIN

	CREATE TEMPORARY TABLE IF NOT EXISTS ones( r int, v int );
	TRUNCATE ones;

	FOR r IN 1 .. array_length( matrix, 1 ) LOOP
	    counting := 0;

	    FOR c IN 1 .. array_length( matrix, 2 ) LOOP
	    	IF matrix[ r ][ c ] = 1 THEN
		   counting := counting + 1;
		END IF;
	    END LOOP;

	    INSERT INTO ones
	    VALUES( r, counting );
	END LOOP;

	SELECT r
	INTO counting
	FROM ones
	WHERE v = ( SELECT max( v ) FROM ones )
	ORDER BY r asc
	LIMIT 1;


	RETURN counting;

END
$CODE$
LANGUAGE plpgsql;



With a temporary table, I store the row number and the counting of the 1 in such row, then with a single query I return the first tuple that match the request.

PWC 271 - Task 2 - PL/PgSQL Implementation

I use a temporay table to store the binary counting of 1 and the number. Then, returning the table sorted appropriately solves the issue.

CREATE OR REPLACE FUNCTION
pwc271.task2_plpgsql( nums int[] )
RETURNS SETOF int
AS $CODE$
DECLARE
	current_number int;
	binary_number bit(8);
	ones int;
BEGIN
	CREATE TABLE IF NOT EXISTS binary_table( i int, v int );
	TRUNCATE binary_table;

	FOREACH current_number IN ARRAY nums LOOP
		binary_number := current_number::bit( 8 );

		SELECT count(*)
		INTO ones
		FROM regexp_split_to_table( binary_number::text, '' ) v
		WHERE v::int = 1;

		INSERT INTO binary_table
		VALUES( ones, current_number );
	END LOOP;

	RETURN QUERY SELECT v
	FROM binary_table
	ORDER BY i ASC, v ASC;

END
$CODE$
LANGUAGE plpgsql;



Java Implementations

PWC 271 - Task 1 - PostgreSQL PL/Java Implementation

I use the stream API to mimic the Perl/Raku implementations.

public class Task1 {

    private final static Logger logger = Logger.getAnonymousLogger();

    @Function( schema = "pwc271",
	       onNullInput = RETURNS_NULL,
	       effects = IMMUTABLE )
    public static final int task1_pljava( int size, int[] matrix ) throws SQLException {
		logger.log( Level.INFO, "Entering pwc271.task1_pljava" );

		Map<Integer, Integer> ones = new HashMap<Integer, Integer>();

		IntStream.range( 0, matrix.length )
		    .forEach( i -> {
			    if ( matrix[ i ] == 1 ) {
					int current_row = i / size;
					ones.putIfAbsent( current_row, 0 );
					ones.put( current_row, ones.get( current_row ) + 1 );
			    }
			} );

		return Collections.min( ones.keySet() );
    }
}



I use an IntStream to loop over all the indexes of the matrix, considering that size indicates the row length. For every index, I increment the value in the ones map, that is then used to find out the min value of the key (i.e., the rows).

PWC 271 - Task 2 - PostgreSQL PL/Java Implementation

Again, a stream API implementation.

public class Task2 {

    private final static Logger logger = Logger.getAnonymousLogger();

    @Function( schema = "pwc271",
	       onNullInput = RETURNS_NULL,
	       effects = IMMUTABLE )
    public static final int[] task2_pljava( int[] nums ) throws SQLException {
		logger.log( Level.INFO, "Entering pwc271.task2_pljava" );

		final Map<String, List<Integer> > binary = new HashMap<String, List<Integer> >();

		Arrays.stream( nums )
		    .forEach( v -> {
			    String bin = Integer.toBinaryString( v );
			    int ones   = bin.split( "1" ).length;
			    binary.putIfAbsent( bin, new LinkedList<Integer>() );
			    binary.get( bin ).add( v );
			} );

		int result[] = new int[ binary.values().size() ];
		int index = 0;
		List<String> keys = new LinkedList<String>( binary.keySet() );
		Collections.sort( keys );
		for ( String bin : keys ) {
		    List<Integer> values = binary.get( bin );
		    Collections.sort( values );
		    for ( int v : values )
			result[ index++ ] = v;
		}

		return result;
    }
}



I convert the array into a stream, and iterate over all the values adding them to the list keyed by the number of ones in the binary representation. Then, a lot of code to order the map and the inner lists and return the flat array.

Python Implementations

PWC 271 - Task 1 - Python Implementation

Similar to the other implementations, I use the special char | to indicate the end of a matrix row. Therefore, the first part of the code is used to built the matrix out of the command line.

import sys

# task implementation
# the return value will be printed
def task_1( args ):
    matrix = []
    row    = 0
    matrix.append( [] )
    for v in args:
        if v == '|':
            row += 1
            matrix.append( [] )
            continue

        matrix[ row ].append( int( v ) )

    ones = {}
    for r in range( 0, len( matrix ) ):
        counting = len( list( filter( lambda x: x == 1, matrix[ r ] ) ) )
        ones[ str( r ) ] = counting

    min_row = None
    for r in ones:
        if ones[ r ] > 0:
            if min_row is None or min_row > int( r ):
                min_row = int( r ) + 1

    return min_row





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



PWC 271 - Task 2 - Python Implementation

The idea is the same as in the other implementations: use a dictioary to store the list of numbers for every coutning of 1 in the binary representation. Note that I sort the list of numbers at every iteration, that is not efficient.

import sys

# task implementation
# the return value will be printed
def task_2( args ):
    binary = {}

    for v in args:
        b = "{0:08b}".format( int( v ) )
        c = 0
        for o in b:
            if o == '1':
                c += 1

        if not c in binary:
            binary[ c ] = []
        binary[ c ].append( int( v ) )
        binary[ c ] = list( sorted( binary[ c ] ) )

    binary = dict( sorted( binary.items() ) )
    result = []
    for b in binary:
        for v in binary[ b ]:
            result.append( v )

    return result


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



The article Perl Weekly Challenge 271: Riff Raff (i.e., the first PWC after the AC/DC live concert!) has been posted by Luca Ferrari on May 27, 2024