Perl Weekly Challenge: Week 242
Best wishes to one and all for a happy Gujarati New Year!
Challenge 1:
Missing Members
You are given two arrays of integers.
Write a script to find out the missing members in each other arrays.
Example 1
Input: @arr1 = (1, 2, 3)
@arr2 = (2, 4, 6)
Output: ([1, 3], [4, 6])
(1, 2, 3) has 2 members (1, 3) missing in the array (2, 4, 6).
(2, 4, 6) has 2 members (4, 6) missing in the array (1, 2, 3).
Example 2
Input: @arr1 = (1, 2, 3, 3)
@arr2 = (1, 1, 2, 2)
Output: ([3])
(1, 2, 3, 3) has 2 members (3, 3) missing in the array (1, 1, 2, 2). Since they are same, keep just one.
(1, 1, 2, 2) has 0 member missing in the array (1, 2, 3, 3).
What the challenge is asking for is the set difference between @arr1
and @arr2
. Raku
has a rich set of set operators which include one=way set difference (the set of elements of set A that are not in set B) — the ∖
operator and symmetric set difference (the set of which elements of set A are not in set B and which elements of Set B are not in set A) — the ⊖
operator. The spec asks for the symmetric set difference so it would
seem we should use ⊖
but that returns one set whereas the examples show two sets (actually lists) in the output. So the code looks like this:
( (@arr1 ∖ @arr2), (@arr2 ∖ @arr1) )
That's the gist of it but actually, my solution is more complicated because I formatted
the results according to the output in the examples plus I have code to create @arr1
and
@arr2
from the command-line.
For Perl, I had to provide my own implementation of the ∖
operator which I did in
the setDifference()
function shown below.
sub setDifference {
As parameters, it takes the two arrays by reference.
my ($arr1, $arr2) = @_;
Then a hash is created whose keys are the elements of @arr1
and the initial value of each key is 0.
my %difference = map { $_ => 0 } @{$arr1};
For each element in @arr2
we see if it exists in %difference
(and therefore in @arr1
.) If it does, that
key is incremented.
for my $elem (@{$arr2}) {
if (exists $difference{$elem}) {
$difference{$elem}++;
}
}
Once all elements in @arr2
have been processed, we can filter %difference
with grep()
to find the
keys whose values remain 0. This list is the set difference. Before returning it, we sort the list because
that is needed to format the results but this step is not strictly necessary.
return sort grep { !$difference{$_} } keys %difference;
}
We use it like this:
( setDifference(\@arr1, \@arr2), setDifference(\@arr2, \@arr1) )
Challenge 2:
Flip Matrix
You are given n x n binary matrix.
Write a script to flip the given matrix as below.
1 1 0
0 1 1
0 0 1
a) Reverse each row
0 1 1
1 1 0
1 0 0
b) Invert each member
1 0 0
0 0 1
0 1 1
Example 1
Input: @matrix = ([1, 1, 0], [1, 0, 1], [0, 0, 0])
Output: ([1, 0, 0], [0, 1, 0], [1, 1, 1])
Example 2
Input: @matrix = ([1, 1, 0, 0], [1, 0, 0, 1], [0, 1, 1, 1], [1, 0, 1, 0])
Output: ([1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 1], [1, 0, 1, 0])
As with challenge 1, the majority of the code I wrote was for extracting the input from the command-line and formatting it for output. The "guts" are this one line:
@matrix = @matrix.map({ $_.reverse.map({ (!$_).Int }) });
The matrix has been read in as an array, @column, where each element is a row in the matrix expressed as an array where each element is a column in that row.
So first, I iterated over the rows with .map()
and reversed each row with .reverse()
and then used .map()
again to iterate over each row flipping the column from 1 to 0 or 0 to 1 using the logical negation (!
) operator. Now, the elements of the matrix having
been input from the command-line are strings. Applying logical negation to a string in
Raku gives us True
or False
values. To get 1's and 0's, the element must be first
converted to a numeric value as their is an implicit conversion from Booleans to numeric 1 and 0. This is done with .Int()
.
This is the Perl version.
@matrix = map { [ map { $_ ^ 1 } reverse @{$_} ] } @matrix;
It is mostly the same as Raku except I used the bit negation operator (^
) to flip elements which avoids the need to convert to an Integer. Why didn't we use the equivalent (+^
) in the Raku version? Unfortunately it seems that Raku's operator works on an entire byte using 2's complement so +^1
is not 0 but -1.