Perl Weekly Challenge 258: arrays of nums

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

The first task was to count how many integers, in a given array, have even digits. This can be solved easily with a single line in Raku:

sub MAIN( *@nums where { @nums.elems == @nums.grep( * ~~ Int ).elems } ) {
    @nums.map( { $_.comb.elems %% 2 ?? 1 !! 0 } ).sum.say;

}



The idea is to map the array so that every value is substituted by 1 if the count of digits is even, and then a sum of the array is done.

PWC 258 - Task 2 - Raku Implementation

Given an integer and an array of integers, compute the sum of only those integers located at an index which binary representation has the keyed number of 1s.

sub MAIN( Int $k where { $k > 0 } , *@nums where { @nums.elems == @nums.grep( * ~~ Int ).elems } ) {
    my @indexes = ( 0 ..^ @nums.elems ).grep( { $_.base( 2 ).comb.grep( * == 1 ).elems == $k } );
    @nums[ @indexes ].sum.say;

}



The @indexes array is computed by grepping the indexes of the input array so that only those indexes that, converted in base( 2 ) (binary) have a number of ones equal to the specified amount $k. Then the array is sliced and summed.

PL/Perl Implementations

PWC 258 - Task 1 - PL/Perl Implementation

Similar to the Raku implementation, but without having a sum function, I iterate on the result of mapping the values into ones.

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

   my ( $numbers ) = @_;

   my @counting = map { split( //, $_ ) % 2 == 0 ? 1 : 0  } ( $numbers->@*  );
   my $sum = 0;
   $sum += $_  for ( @counting );
   return $sum;

$CODE$
LANGUAGE plperl;



PWC 258 - Task 2 - PL/Perl Implementation

Here I create an utility function $count_binary_ones() that is used to simplify the grep done on every index of the array. Within such utility function, I convert the input number (the array index) into a binary form, split it and count how many digits are 1. Having the resulting indexes, it is simple to iterate over the array and sum the content.

CREATE OR REPLACE FUNCTION
pwc258.task2_plperl( int, int[] )
RETURNS int
AS $CODE$

   my ( $k, $numbers ) = @_;

   my $count_binary_ones = sub {
      my $num = shift;
      my @digits = split //, sprintf( '%b', $num );
      return scalar( grep { $_ == 1 } @digits );
   };

   my @indexes = grep { $count_binary_ones->( $_ ) == $k } ( 0 .. $numbers->@* - 1 );
   my $sum = 0;
   $sum += $numbers->@[ $_ ] for ( @indexes );
   return $sum;

$CODE$
LANGUAGE plperl;



PostgreSQL Implementations

PWC 258 - Task 1 - PL/PgSQL Implementation

A single query can solve the task: the CTE reports every number with the count of digits, and the external query counts how many numbers have an even number of digits.

CREATE OR REPLACE FUNCTION
pwc258.task1_plpgsql( nums int[] )
RETURNS int
AS $CODE$
   WITH q_nums AS (
   	SELECT v, array_length( regexp_split_to_array( v::text, '' ), 1 ) as c
	FROM unnest( nums ) v
	)
	SELECT count( * )
	FROM q_nums
	WHERE c % 2 = 0;

$CODE$
LANGUAGE sql;



PWC 258 - Task 2 - PL/PgSQL Implementation

Here I need to iterate on every array index (starting from 1), convert it into a binary string (assuming 8 bits suffice), and sum all the digits of the binary representation. If the sum is equal to the input argument, the v_sum summary of the array content is updated.

CREATE OR REPLACE FUNCTION
pwc258.task2_plpgsql( k int, nums int[] )
RETURNS int
AS $CODE$
DECLARE
	v_sum int := 0;
	count_of_ones int := 0;
BEGIN
	FOR i IN 1 .. array_length( nums, 1 ) LOOP
		SELECT sum( v::int )
		INTO count_of_ones
		FROM regexp_split_to_table( i::bit( 8 )::text, '' ) v;

		IF count_of_ones <> k THEN
		   continue;
		END IF;

		v_sum := v_sum + nums[ i ];
	END LOOP;

	RETURN v_sum;
END
$CODE$
LANGUAGE plpgsql;



Java Implementations

PWC 258 - Task 1 - PostgreSQL PL/Java Implementation

Quite simple to implement in Java: if the length() of the string representing the number has an even number of characters, then the element is accounted.

public class Task1 {

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

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

		int count = 0;
		for ( int current : nums )
		    count += String.format( "%d", current ).length() % 2 == 0 ? 1 : 0;

		return count;
    }
}



The same task can be rewritten using teh stream API:

public class Task1 {

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

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

		List<Integer> numbers = new LinkedList<Integer>();
		for ( int current : nums )
		    numbers.add( current );

		int count = numbers.stream().mapToInt( current -> {
			if ( String.format( "%d", current ).length() % 2 == 0 )
			    return 1;
			else
			    return 0;
		    } ).sum();

		return count;
    }
}



In the above, the list of numbers is mapToInt and the lambda expression uses the current variable placeholder, returning 1 or 0 if the value contains an even number of digits, and then sum does the trick.

PWC 258 - Task 2 - PostgreSQL PL/Java Implementation

A nested loop to the rescue: I iterate over all the indexes, and then convert it to a string to count all the digits equal to 1.

public class Task2 {

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

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

		int sum = 0;
		int count = 0;
		for ( int i = 0; i < nums.length; i++ ) {
		    count = 0;
		    for ( String d : Integer.toBinaryString( i ).split( "" ) )
			if ( d.equals( "1" ) )
			    count++;


		    if ( count == k )
			sum += nums[ i ];
		}

		return sum;
    }
}



The same result can be achieved with the stream API:

public class Task2 {

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

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

			return IntStream.range( 0, nums.length )
			    .map( current -> {
				    int ones  = 0;
				    for ( String d : Integer.toBinaryString( current ).split( "" ) )
					if ( d.equals( "1" ) )
					    ones ++;


				    if ( ones  == k )
						return nums[ current ];
				    else
						return 0;

				} ).sum();

    }
}



Here the IntStream, an utility stream made only of integers, is used to traverse the indexes of the nums array, and every item is mapped to the value at which the index points to, in the case the test pass, or zero in the case of failure. Then the sum does the trick.

Python Implementations

PWC 258 - Task 1 - Python Implementation

Since Python allows for a len of a string, it is quite simple to count the length (and hence, if the number of digits is even) of a given input value. This solution mimics the Java one.

import sys

# task implementation
# the return value will be printed
def task_1( args ):
    sum = 0
    for n in args:
        if len( n ) % 2 == 0:
            sum += 1

    return sum


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



PWC 258 - Task 2 - Python Implementation

A very unreadable solution!

import sys


# task implementation
# the return value will be printed
def task_2( args ):
    k = int( args[ 0 ] )
    nums = list( map( int, args[ 1: ] ) )

    def is_index_ok( v, k ):
        b = '{0:08b}'.format( v )
        count = sum( map( int, list( '{0:08b}'.format( v ) ) ) )
        return count == k

    indexes = list( filter( lambda i: is_index_ok( i, k ),
                            range(0, len( nums ) ) ) )

    summy = 0
    for i in indexes:
        summy += nums[ i ]

    return summy


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



I define a is_index_ok function that accepts a number, converts it into a binary string (assuming 8 bits suffice), and convert the string into a list, then mapping into integers and summing it. This produces the count of 1 in the index binary value. Then, the function returns True if the count of 1 is equal to the k value. The function is then used as the filter criteria into the filtering of the indexes, so to get the indexes array to sum, that are then summed into a summy result.

The article Perl Weekly Challenge 258: arrays of nums has been posted by Luca Ferrari on February 26, 2024