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) )

(Full code on Github.)

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) )

(Full code on Github.)

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 }) });

(Full code on Github.)

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;

(Full code on Github.)

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.