# Perl Weekly Challenge 235: integer arrays

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

The first task was about discovering if a given input array of integers is naturally sorted removing only one item.

``````sub MAIN( *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {

for 0 ..^ @nums.elems {
my @current;
@current.push: | @nums[ 0 .. \$_ - 1 ] if \$_ != 0;
@current.push: | @nums[ \$_ + 1 ..^ @nums.elems ];

'true'.say and exit if @current ~~ @current.sort;
}

'false'.say;
}
``````

I build at every step an array made by a slice of the original array, and compare it with its sorted version. If both the array are the same, the result is `true`.

## PWC 235 - Task 2 - Raku Implementation

The second task was about duplicating every `0` found in a given array of integers, without exceeding the array size, that means trailing the extra digits.

``````sub MAIN( *@nums where { @nums.grep( * ~~ Int ).elems == @nums.elems } ) {

my @result;
for 0 ..^ @nums.elems {
@result.push: 0  if @nums[ \$_ ] == 0;
# add the number, even if it is a zero, duplicated
# from the row above
@result.push: @nums[ \$_ ];
}

@result[ 0 ..^ @nums.elems ].join( ',' ).say;
}

``````

I add every digit to the `@result` array, and add it twice if it is a zero. In the end, I output only the slice of the array.

# PL/Perl Implementations

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

A bit by bit similar solution to the Raku one.

``````CREATE OR REPLACE FUNCTION
RETURNS boolean
AS \$CODE\$
my ( \$nums ) = @_;

for ( 0 .. \$nums->@* - 1 ) {
my @current;
push @current, \$nums->@[ 0 .. \$_ - 1 ] if ( \$_ != 0 );
push @current, \$nums->@[ \$_ + 1 .. \$nums->@* - 1 ];

return 1 if ( join( ',', @current ) eq join( ',', sort @current ) );
}

return 0;
\$CODE\$
LANGUAGE plperl;

``````

This time, I compare the stringified version of the array and of the sorted one to see it if matches.

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

This time I return every digit when I encounter it, stopping when the max size is found.

``````CREATE OR REPLACE FUNCTION
RETURNS SETOF int
AS \$CODE\$
my ( \$nums ) = @_;
my \$remaining = \$nums->@* - 1;

for ( \$nums->@* ) {

return_next( \$_ );
\$remaining--;
return undef if \$remaining <= 0;

return_next( 0 ) if ( \$_ == 0 );
\$remaining--;
return undef if \$remaining <= 0;

}

return undef;
\$CODE\$
LANGUAGE plperl;

``````

# PostgreSQL Implementations

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

A quite verbose solution, but nothing better came into my mind.

``````CREATE OR REPLACE FUNCTION
RETURNS boolean
AS \$CODE\$
DECLARE
current_array int[];
string_array  text;
string_sorted text;
BEGIN

SELECT string_agg( x::text, ',' )
INTO string_array
FROM ( SELECT unnest( nums ) y ORDER BY 1 ) x
ORDER BY 1;

FOR i IN 1 .. array_length( nums, 1 ) LOOP

current_array := '{}';

IF i <> 1 THEN
current_array := current_array || nums[ 1 : ( i - 1 ) ];
END IF;

current_array := current_array || nums[ ( i + 1 ) : ];

SELECT string_agg( x::text, ',' )
INTO string_sorted
FROM ( SELECT y::text FROM unnest( current_array ) y ORDER BY 1 ) x
;

SELECT string_agg( x::text, ',' )
INTO string_array
FROM ( SELECT y::text FROM unnest( current_array ) y ) x
;

IF string_sorted = string_array THEN
RETURN true;
END IF;

END LOOP;

RETURN false;
END
\$CODE\$
LANGUAGE plpgsql;

``````

The idea is to slice the original array into one that has all elements except one. Then I build a string representation of the built array and of the sorted one, and if the strings are the same, I can stop.

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

Simple solution using the same PL/Perl approach: return every digit, return a zero twice, stop as soon as the max size is reached.

``````CREATE OR REPLACE FUNCTION
RETURNS SETOF int
AS \$CODE\$
DECLARE
current_element int;
remaining int;
BEGIN
remaining := array_length( nums, 1 );

FOREACH current_element IN ARRAY nums LOOP
RETURN NEXT current_element;
remaining := remaining - 1;

IF remaining = 0 THEN
RETURN;
END IF;

IF current_element = 0 THEN
RETURN NEXT 0;
remaining := remaining - 1;
END IF;

IF remaining = 0 THEN
RETURN;
END IF;

END LOOP;

RETURN;
END
\$CODE\$
LANGUAGE plpgsql;

``````

The article Perl Weekly Challenge 235: integer arrays has been posted by Luca Ferrari on September 18, 2023