This is my response to The Weekly Challenge #381.
n x n matrix containing integers from 1 to n.
Input: @matrix = ([1, 2, 3, 4],
[2, 3, 4, 1],
[3, 4, 1, 2],
[4, 1, 2, 3],)
Output: true
Example 2:
Input: @matrix = ([1])
Output: true
Example 3:
Input: @matrix = ([1, 2, 5],
[5, 1, 2],
[2, 5, 1],)
Output: false
Elements are out of range 1..3.
Example 4:
Input: @matrix = ([1, 2, 3],
[1, 2, 3],
[1, 2, 3],)
Output: false
Example 5:
Input: @matrix = ([1, 2, 3],
[3, 1, 2],
[3, 2, 1],)
Output: false
Note the use of my «matrix as a string» syntax in this program, see e.g. the default matrix in [3] or the examples. It was last used in «find-celebrity», the second part of Celebrity Representation, my response to challenge #361.
File: same-row-column#! /usr/bin/env raku
unit sub MAIN ($string = "1 2 5 | 5 1 2 | 2 5 1",
:v(:$verbose));
my $matrix = $string.split("|")>>.words>>.Numeric;
my $rows = $matrix.elems;
my $cols = $matrix[0].elems;
my @target = 1 .. $cols;
die "The rows must have the same size"
unless [==] $matrix>>.elems;
die "The matrix must have the same number of rows and columns"
unless $rows == $cols;
die "Must contain integers only"
unless all($matrix[*;*]) ~~ Int;
if $verbose
{
say ":Matrix: { $matrix.raku }";
say ":Target: @target[]";
}
say same-row-column($matrix, @target);
sub same-row-column ($matrix, @target)
{
for ^$cols -> $col
{
my @col = $matrix[*;$col];
my @col-sort = @col.sort;
my $is-ok = @col-sort eqv @target;
say ":Column $col: @col[] is { $is-ok ?? "ok" !! "not ok" }"
if $verbose;
return False unless $is-ok;
my @row = $matrix[$col];
my @row-sort = @row.sort;
$is-ok = @col-sort eqv @target;
say ":Row $col: @row[] is { $is-ok ?? "ok" !! "not ok"}"
if $verbose;
return False unless $is-ok;
}
return True;
}
[3] A default matrix, in case the user does not supply one.
[6] Split the rows on the | and the individual row items on
space(s). Coerce the whole shebang to numeric values (i.e. crash
on non-numeric values).
[7] The number of rows.
[8] The number of columns, taken from the first row.
[9] An array containing the target values.
[11] Ensure that all the rows
have the same size, with the Reduction Metaoperator []
with == as the operator.
See docs.raku.org/language/operators#Reduction_metaoperators for more information about the Reduction Metaoperator [].
[14] Ensure that the number of rows and columns are equal.
[17] Ensure that the matrix only contains integers.
Skipping this line, and replacing Numeric in [6]
with int is a possibility, but it would (silently) truncate
non-integer numeric values to integers. You really do not want
that.
[26] Fire off the check.
[28] The procedure doing the check. Note that $verbose is
a global variable, which is a bad (or lazy) design choice.
[30] Iterate over the column (and row) indices.
[32] Extract the column values.
[33] Sort those values, so that we can compare them.
[34] Compare the sorted values from the column with
the target, using the eqv operator (as it works on data
structures).
See docs.raku.org/routine/eqv for more information about eqv.
[39] Report failure (False) if they do not match up.
[41-48] The same for the row data.
[51] Failure to fail (in any of the [39] and [48] in the loop) means success.
Running it:
$ ./same-row-column "1 2 3 4 | 2 3 4 1 | 3 4 1 2 | 4 1 2 3"
True
$ ./same-row-column "1"
True
$ ./same-row-column "1 2 5 | 5 1 2 | 2 5 1"
False
$ ./same-row-column "1 2 3 | 1 2 3 | 1 2 3"
False
$ ./same-row-column "1 2 3 | 3 1 2 | 3 2 1"
False
Looking good.
With verbose mode:
$ ./same-row-column -v "1 2 3 4 | 2 3 4 1 | 3 4 1 2 | 4 1 2 3"
:Matrix: $([1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3])
:Target: 1 2 3 4
:Column 0: 1 2 3 4 is ok
:Column 0: 1 2 3 4 is OK
:Row 0: 1 2 3 4 is ok
:Column 1: 2 3 4 1 is ok
:Column 1: 2 3 4 1 is OK
:Row 1: 2 3 4 1 is ok
:Column 2: 3 4 1 2 is ok
:Column 2: 3 4 1 2 is OK
:Row 2: 3 4 1 2 is ok
:Column 3: 4 1 2 3 is ok
:Column 3: 4 1 2 3 is OK
:Row 3: 4 1 2 3 is ok
True
$ ./same-row-column -v "1"
:Matrix: $([1],)
:Target: 1
:Column 0: 1 is ok
:Column 0: 1 is OK
:Row 0: 1 is ok
True
$ ./same-row-column -v "1 2 5 | 5 1 2 | 2 5 1"
:Matrix: $([1, 2, 5], [5, 1, 2], [2, 5, 1])
:Target: 1 2 3
:Column 0: 1 5 2 is not ok
False
$ ./same-row-column -v "1 2 3 | 1 2 3 | 1 2 3"
:Matrix: $([1, 2, 3], [1, 2, 3], [1, 2, 3])
:Target: 1 2 3
:Column 0: 1 1 1 is not ok
False
$ ./same-row-column -v "1 2 3 | 3 1 2 | 3 2 1"
:Matrix: $([1, 2, 3], [3, 1, 2], [3, 2, 1])
:Target: 1 2 3
:Column 0: 1 3 3 is not ok
False
Input: @int = (2,4)
Output: 0
Not enough elements in the array.
Example 2:
Input: @int = (1, 1, 1, 1)
Output: 0
Example 3:
Input: @int = (1, 1, 4, 8, 12, 12)
Output: 2
The elements are 4 and 8.
Example 4:
Input: @int = (3, 6, 6, 9)
Output: 2
Both instances of 6.
Example 5:
Input: @int = (0, -5, 10, -2, 4)
Output: 3
The elements are 0, -2, and 4.
#! /usr/bin/env raku
unit sub MAIN (*@ints where @ints.elems > 0 && all(@ints) ~~ Int,
:v(:$verbose))
{
my $min = @ints.min;
my $max = @ints.max;
my @strictly = @ints.grep( $min < * < $max );
if $verbose
{
say ":Min: $min";
say ":Max: $max";
say ":Strictly: @strictly[]";
}
say @strictly.elems;
}
[3] At least one element, and all of them must be integers.
[6] The minimum value with min.
See docs.raku.org/routine/min for more information about min.
[7] The maximum value with max.
See docs.raku.org/routine/max for more information about max.
[8] The «strictly» values, i.e. values greater than
$min and smaller than $max. We use grep to get
them.
See docs.raku.org/routine/grep for more information about grep.
[17] Print the number of «strictly» values.
Running it:
$ ./smaller-greater-element 2 4
0
$ ./smaller-greater-element 1 1 1 1
0
$ ./smaller-greater-element 1 1 4 8 12 12
2
$ ./smaller-greater-element 3 6 6 9
2
$ ./smaller-greater-element 0 -5 10 -2 4
3
Looking good.
With verbose mode:
$ ./smaller-greater-element -v 2 4
0
$ ./smaller-greater-element -v 1 1 1 1
:Min: 1
:Max: 1
:Strictly:
0
$ ./smaller-greater-element -v 1 1 4 8 12 12
:Min: 1
:Max: 12
:Strictly: 4 8
2
$ ./smaller-greater-element -v 3 6 6 9
:Min: 3
:Max: 9
:Strictly: 6 6
2
$ ./smaller-greater-element -v 0 -5 10 -2 4
:Min: -5
:Max: 10
:Strictly: 0 -2 4
3
And that's it.