Perl Weekly Challenge: Week 84
Challenge 1:
Reverse Integer
You are given an integer
$N
.Write a script to reverse the given integer and print the result. Print 0 if the result doesn’t fit in 32-bit signed integer.
The number
2,147,483,647
is the maximum positive value for a 32-bit signed binary integer in computing.
Example 1:
Input: 1234
Output: 4321
Example 2:
Input: -1234
Output: -4321
Example 3:
Input: 1231230512
Output: 0
This is the code I wrote for Perl based on a C function I had written some time ago. In hindsight this could be a lot more perlish.
my $num = shift;
my $sign = 0;
if ($num < 0) {
$sign = 1;
$num = abs($num);
}
if ($num > 2_147_483_647) {
say '0';
} else {
For instance I could have replaced the entire while
loop by treating $num
as a
string and reversing it with the reverse()
function.
my $reversed = 0;
while ($num > 0) {
$reversed = $reversed * 10 + $num % 10;
$num = int ($num / 10);
}
say $sign ? q{-} : q{}, $reversed;
}
The same criticism applies to the Raku version but, oh well, atleast it works.
sub MAIN(Int $n) {
Because function parameters are immutable, $n
needs to be copied to another variable
if we want to slice and dice it.
my $num = $n;
I could have used True
and False
for $sign
as Raku has a boolean type.
my $sign = 0;
if ($num < 0) {
$sign = 1;
$num = abs($num);
}
if $num > 2_147_483_647 {
say '0';
} else {
my $reversed = 0;
while $num > 0 {
$reversed = $reversed * 10 + $num % 10;
In Perl I had to use the int()
function to make sure the result of the division was
an integer. Raku has an integer division operator, div
so it's not necessary here.
$num div= 10;
}
say $sign ?? q{-} !! q{}, $reversed;
}
}
Challenge 2:
Flip Array
You are given matrix of size
m x n
with only1
and0
.Write a script to find the count of squares having all four corners set as
1
.
Example 1:
Input: [ 0 1 0 1 ]
[ 0 0 1 0 ]
[ 1 1 0 1 ]
[ 1 0 0 1 ]
Output: 1
EXPLANATION
There is one square (3x3) in the given matrix with four corners as 1 starts at r=1;c=2.
[ 1 0 1 ]
[ 0 1 0 ]
[ 1 0 1 ]
Example 2:
Input: [ 1 1 0 1 ]
[ 1 1 0 0 ]
[ 0 1 1 1 ]
[ 1 0 1 1 ]
Output: 4
EXPLANATION
There is one square (4x4) in the given matrix with four corners as 1 starts at r=1;c=1.
There is one square (3x3) in the given matrix with four corners as 1 starts at r=1;c=2.
There are two squares (2x2) in the given matrix with four corners as 1. First starts at r=1;c=1 and second starts at r=3;c=3.
Example 3:
Input: [ 0 1 0 1 ]
[ 1 0 1 0 ]
[ 0 1 0 0 ]
[ 1 0 0 1 ]
Output: 0
I'll show you the Raku solution first.
sub MAIN(
Str $file #= a file describing a matrix of 1's and 0's where every line
#= is a row in the matrix.
) {
my @matrix;
As entering a matrix on the command line would have been a bit awkward, I elected
to read in text files where each row of 1's and 0's would be a separate line.
This code reads such a file in and populates a 2d array, @matrix
with the separated digits.
If this code were being used in a production script, I would do a lot of checking to make sure
it is in the correct format. As it stands, it just trusts the input will be usable.
for $file.IO.lines -> $line {
@matrix.push($line.comb);
}
my $squares = 0;
A double for
loop sets up each row of the matrix as $m
and each column as $n
.
As we traverse the matrix, each element is checked if it is a 1. If it is, another
loop is started, this time a C-style for
loop; Raku reserves the for
keyword for
iteration over ranges and uses loop
for the C-style one. This loop increments $side
until we get to another 1
or we hit the right hand edge of the matrix.
If we did find a second 1
, we have the top two corners of a square. We now go
down $side
rows (once again bounds checking) and then accross $side
columns and see
if there are 1
's in those two locations. If there are, we have a square.
In production code I would consider 5 nested blocks as a code smell and try and refactor this into several functions.
for 0 ..^ @matrix.elems -> $m {
for 0 ..^ @matrix[$m].elems -> $n {
if @matrix[$m][$n] == 1 {
loop (my $side = 1; $n + $side < @matrix[$m].elems; $side++) {
if @matrix[$m][$n + $side] == 1
&& $m + $side < @matrix.elems
&& @matrix[$m + $side][$n] == 1
&& @matrix[$m + $side][$n + $side] == 1 {
$squares++;
}
}
}
}
}
say $squares;
}
And this is Perl. The chief thing to note here is that Perl doesn't have real multidimensional arrays so our matrix is an array of array references which makes accessing elements a bit awkward.
my $file = shift // usage();
my @matrix;
open my $fn, '<', $file or die "$OS_ERROR\n";
while (my $line = <$fn>) {
chomp $line;
push @matrix, [ split //, $line ];
}
close $fn;
my $squares = 0;
for my $m (0 .. scalar @matrix - 1) {
for my $n (0 .. (scalar @{$matrix[$m]} - 1)) {
if ($matrix[$m]->[$n] == 1) {
for (my $side = 1; $n + $side < scalar @{$matrix[$m]}; $side++) {
if ($matrix[$m]->[$n + $side] == 1
&& $m + $side < scalar @matrix
&& $matrix[$m + $side]->[$n] == 1
&& $matrix[$m + $side]->[$n + $side] == 1) {
$squares++;
}
}
}
}
}
say $squares;