# Perl Weekly Challenge 268: arrays and slices

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

The first task was to find the magic number between two equally sized arrays of integers. The magic n umber is the difference between two elements of the arrays so that from the first array you can obtain the second one, even if in a different order. Essentially, it means that the sorted arrays have values with a consistent difference.

``````sub MAIN(  :@left,  :@right where { @left.elems == @right.elems }  ) {
my @sorted-left  = @left.sort;
my @sorted-right = @right.sort;

my @diffs;
for 0 ..^ @sorted-left.elems -> \$i {
my \$current = @sorted-left[ \$i ] - @sorted-right[ \$i ];
@diffs.push: \$current if ! @diffs.grep( \$current );
}

@diffs[ 0 ].say and exit  if @diffs.elems == 1;
'Impossible'.say;
}

``````

I first sort the arrays, then I iterate and compute the `\$current` difference between sorted cells, and add it the list of `@diffs` if not already inserted. In the end, if the list of `@diffs` has only one element, that is the magic number, otherwise the magic number does not exist.

## PWC 268 - Task 2 - Raku Implementation

The second task was about sorting a given input array of integers by sorting its two elements slices.

``````sub MAIN( *@nums where { @nums.elems == @nums.grep( * ~~ Int ).elems  && @nums.elems %% 2 }  ) {
my @sorted;
for @nums.sort.rotor( 2 ) -> @couple {
@sorted.push: @couple.reverse.flat;
}

@sorted.join( " " ).say;
}

``````

I use the `rotor` that automatically splits the array in sub elements of two parts, and sort the subarray in the way required, then pushing as a flat list into the output result `@sorted`.

# PL/Perl Implementations

## PWC 268 - Task 1 - PL/Perl Implementation

The same implementation as in Raku.

``````CREATE OR REPLACE FUNCTION
RETURNS int
AS \$CODE\$

my ( \$left, \$right ) = @_;

die 'Array must have the same length!' if ( \$left->@* != \$right->@* );

my @diffs;
for my \$index ( 0 .. \$left->@* - 1 ) {
my \$d = \$left->@[ \$index ] - \$right->@[ \$index ];
push @diffs, \$d if ( ! grep( { \$_ == \$d } @diffs ) );
}

return \$diffs[ 0 ] if ( @diffs == 1 );
return undef;

\$CODE\$
LANGUAGE plperl;

``````

## PWC 268 - Task 2 - PL/Perl Implementation

Same implementtion as in Raku, but since I don’t have the `rotor`, I extract the couple of elements and sort them manually.

``````CREATE OR REPLACE FUNCTION
RETURNS SETOF int
AS \$CODE\$

my ( \$nums ) = @_;

\$nums = [ sort \$nums->@* ];
my @sorted;
for my \$index ( 0 .. \$nums->@* - 1 ) {
next if \$index % 2 != 0;
push @sorted, reverse sort( \$nums->@[ \$index ], \$nums->@[ \$index + 1 ] );
}

return [ @sorted ]	;

\$CODE\$
LANGUAGE plperl;

``````

# PostgreSQL Implementations

## PWC 268 - Task 1 - PL/PgSQL Implementation

A single query, with a CTE, can solve the problem.

``````CREATE OR REPLACE FUNCTION
pwc268.task1_plpgsql( l int[], r int[] )
RETURNS int
AS \$CODE\$

WITH sorted_left AS ( SELECT v, row_number()  OVER ( order by 1 ) as r  FROM unnest( l ) v  )
, sorted_right AS ( SELECT v, row_number()  OVER ( order by 1 ) as r  FROM unnest( r ) v  )
, diffs AS (
SELECT l.v - r.v as d
FROM sorted_left l, sorted_right r
WHERE l.r = r.r
)
SELECT d
FROM diffs d
GROUP BY d
HAVING count(*) = ( SELECT array_length( l, 1 ) );

\$CODE\$
LANGUAGE sql;

``````

I use the `row_number()` function to get the position of every sorted element, so that I can compute the differences between elements with the same index (i.e., position), and then I select only the difference that appears the exact number as the length of the array.

## PWC 268 - Task 2 - PL/PgSQL Implementation

Here I cheated, I call the PL/Perl implementation.

``````CREATE OR REPLACE FUNCTION
RETURNS SETOF int
AS \$CODE\$
\$CODE\$
LANGUAGE sql;

``````

# Java Implementations

## PWC 268 - Task 1 - PostgreSQL PL/Java Implementation

The idea is the same as in PL/Perl approach: I sort the lists of integers and compute all the differences, returning the found value if there is only one.

``````public class Task1 {

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

@Function( schema = "pwc268",
onNullInput = RETURNS_NULL,
effects = IMMUTABLE )
public static final Integer task1_pljava( int[] left, int[] right ) throws SQLException {

for ( int i : left )
for ( int i : right )

Collections.sort( l );
Collections.sort( r );

for ( int i = 0; i < l.size(); i++ ) {
int current = l.get( i ) - r.get( i );
if ( ! diffs.contains( current ) )
}

if ( diffs.size() == 1 )
return diffs.get( 0 );
else
return null;

}
}

``````

## PWC 268 - Task 2 - PostgreSQL PL/Java Implementation

Same approach as in PL/Perl: extract the single couple of elements of every slice and manually sort them by means of the ternary operator.

``````public class Task2 {

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

@Function( schema = "pwc268",
onNullInput = RETURNS_NULL,
effects = IMMUTABLE )
public static final int[] task2_pljava( int[] nums ) throws SQLException {

for ( int i : nums )
Collections.sort( nums );

int[] result = new int[ nums.length ];
int index = 0;

for ( int i = 0; i < sorted.size(); i++ ) {
int left = sorted.get( i );
int right = sorted.get( ++i );

result[ index++ ]   = ( left > right ? left : right );
result[ index++ ] = ( left > right ? right : left );
}

return result;
}
}

``````

# Python Implementations

## PWC 268 - Task 1 - Python Implementation

Same approach as in PL/Perl, but since there is no common way to pass two different arrays on the command line, I use the `|` as a separator.

``````def task_1( args ):
left = []
right = []

left  = list( map( int, args[ 0 : args.index( "|" ) ] ) )
right = list( map( int, args[ args.index( "|" ) + 1 : ] ) )

left.sort()
right.sort()

diffs = []
for index in range( 0, len( left ) ):
d = left[ index ] - right[ index ]
if not d in diffs:
diffs.append( d )

if len( diffs ) == 1:
return diffs[ 0 ]
else:
return None

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

``````

## PWC 268 - Task 2 - Python Implementation

Same approach already implemented in PL/Java.

``````def task_2( args ):
sorted = list( map( int, args ) )
sorted.sort()

result = []

for i in range( 0, len( sorted ) ):
if i % 2 != 0:
continue

left  = sorted[ i ]
right = sorted[ i + 1 ]

result.append( left if left > right else right )
result.append( left if right > left else right )

return result

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

``````

The article Perl Weekly Challenge 268: arrays and slices has been posted by Luca Ferrari on May 8, 2024