Weekly Challenge 381
Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. Unless otherwise stated, Copilot (and other AI tools) have NOT been used to generate the solution. It's a great way for us all to practice some coding.
The etymology of this weeks title is the use of set in the Python solution, grep in the Perl solution, matching items in a list/array and a nod to the Wimbledon Grand Slam.
Task 1: Same Row Column
Task
You are given a n × n matrix containing integers from 1 to n.
Write a script to find if every row and every column contains all the integers from 1 to n.
My solution
For input from the command line, I take a JSON-fomatted string which is converted to a list (array in Perl) called matrix.
For the Python solution, I start by checking that the matrix is square.
def same_row_column(matrix: list[list[int]]) -> bool:
length = len(matrix)
for row in matrix:
if len(row) != length:
raise ValueError("All rows must have the same length")
I then create a set of the expected values of each row and column.
expected_set = set(range(1, length+1))
Finally I check each row and each column meets the criteria. If it doesn't, I return False. If all checks pass, I return True. Sets are unordered so {1, 2, 3} is equal to {3, 2, 1}.
for i in range(length):
if set(matrix[i]) != expected_set:
return False
if set(matrix[r][i] for r in range(length)) != expected_set:
return False
return True
Perl does not have sets, so the solution is slightly different. I start by creating a function called check_values. This checks that every value from 1 to n (the length of the matrix) is present. It will return 1 if it is, or 0 if it isn't.
use List::Util 'none';
sub check_values (@ints) {
# Check that each number from 1 to the length of ints is present
for my $i ( 1 .. $#ints + 1 ) {
if ( none { $_ == $i } @ints ) {
return 0;
}
}
return 1;
}
The rest of the code follows the same logic as the Python solution. It uses the map function to retrieve the columns as required.
sub main ($matrix_json) {
my $matrix = decode_json($matrix_json);
my $length = scalar(@$matrix);
foreach my $row (@$matrix) {
if ( scalar(@$row) != $length ) {
die "All rows must have the same length\n";
}
}
foreach my $i ( 0 .. $#$matrix ) {
if ( not check_values( @{ $matrix->[$i] } ) ) {
say 'false';
return;
}
if ( not check_values( map { $_->[$i] } @$matrix ) ) {
say 'false';
return;
}
}
say 'true';
}
Examples
$ ./ch-1.py "[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]"
True
$ ./ch-1.py "[[1]]"
True
$ ./ch-1.py "[[1, 2, 5], [5, 1, 2], [2, 5, 1]]"
False
$ ./ch-1.py "[[1, 2, 3], [1, 2, 3], [1, 2, 3]]"
False
$ ./ch-1.py "[[1, 2, 3], [3, 1, 2], [3, 2, 1]]"
False
Task 2: Smaller Greater Element
Task
You are given an array of integers.
Write a script to find the number of elements that have both a strictly smaller and greater element in the given array.
My solution
Unless I'm missing something obvious, this task is to count the number of items that aren't the lowest or higher number. For this task, I create a set of the lowest and highest number called excluded_values and then count the number items that aren't in the set.
def smaller_greater_element(ints: list[int]) -> int:
excluded_values = {min(ints), max(ints)}
return sum(1 for i in ints if i not in excluded_values)
For the Perl solution, I create two variables min_value and max_value. I then use the grep function to count the number of items isn't one of the value. The function will return the number of items in the array if it is assigned to a scalar.
use List::Util qw(max min);
sub main (@ints) {
my $min_value = min(@ints);
my $max_value = max(@ints);
my $count = grep { $_ != $min_value && $_ != $max_value } @ints;
say $count;
}
Examples
$ ./ch-2.py 2 4
0
$ ./ch-2.py 1 1 1 1
0
$ ./ch-2.py 1 1 4 8 12 12
2
$ ./ch-2.py 3 6 6 9
2
$ ./ch-2.py 0 -5 10 -2 4
3
Top comments (0)