This is my response to The Weekly Challenge #337.
@num1
.
@num2
, where $num2[i]
is the count of all numbers less than or equal to $num1[i]
.
Input: @num1 = (6, 5, 4, 8)
Output: (2, 1, 0, 3)
index 0: numbers <= 6 are 5, 4 => 2
index 1: numbers <= 5 are 4 => 1
index 2: numbers <= 4, none => 0
index 3: numbers <= 8 are 6, 5, 4 => 3
Example 2:
Input: @num1 = (7, 7, 7, 7)
Output: (3, 3, 3, 3)
Example 3:
Input: @num1 = (5, 4, 3, 2, 1)
Output: (4, 3, 2, 1, 0)
Example 4:
Input: @num1 = (-1, 0, 3, -2, 1)
Output: (1, 2, 4, 0, 3)
Example 5:
Input: @num1 = (0, 1, 1, 2, 0)
Output: (1, 3, 3, 4, 1)
It follows from the very first example that the value itself should not be included in the count. The second example shows that this only applies to the element itself, and not duplicate values.
File: smaller-than-current
#! /usr/bin/env raku
unit sub MAIN (*@num1 where @num1.elems > 0 # [1]
&& all(@num1) ~~ Numeric); # [1a]
say @num1.map({ @num1.grep( * <= $_ ).elems -1 });
# [2] ##### ##
# [3] ########################
[1] At least one element, and all of them must satisfy the Numeric type
Num
. Note that this does not change the type of the values in any
way, so e.g. an integer input will stay an integer (or IntStr, rather, if
you are fussy).
[2] The outer map
is just a loop, giving the count for
each initial value. The current value is available as $_
because
of the {
and }
wrapping the code.
See docs.raku.org/routine/map for more information about map
.
[3] The inner grep
does not use the {
and
}
wrappers, so the current value is available as *
instead of $_
. We get the number of values less than or equal to
the original value (from [2]), subtracting 1 to compensate for the
fact that it should not count itself.
See docs.raku.org/routine/grep for more information about grep
.
Running it:
$ ./smaller-than-current 6 5 4 8
(2 1 0 3)
$ ./smaller-than-current 7 7 7 7
(3 3 3 3)
$ ./smaller-than-current 5 4 3 2 1
(4 3 2 1 0)
$ ./smaller-than-current -- -1 0 3 -2 1
(1 2 4 0 3)
$ ./smaller-than-current 0 1 1 2 0
(1 3 3 4 1)
It is certainly possible to add verbose mode to the program, but then it
would not be a oneliner (ignore the unit sub
line)
anymore.
row
and col
, also a list of positions in the
matrix.
Input: $row = 2, $col = 3, @locations = ([0,1],[1,1])
Output: 6
Initial:
[ 0 0 0 ]
[ 0 0 0 ]
Apply [0,1]:
Increment row 0:
Before After
[ 0 0 0 ] [ 1 1 1 ]
[ 0 0 0 ] [ 0 0 0 ]
Increment col 1:
Before After
[ 1 1 1 ] [ 1 2 1 ]
[ 0 0 0 ] [ 0 1 0 ]
Apply [1,1]:
Increment row 1:
Before After
[ 1 2 1 ] [ 1 2 1 ]
[ 0 1 0 ] [ 1 2 1 ]
Increment col 1:
Before After
[ 1 2 1 ] [ 1 3 1 ]
[ 1 2 1 ] [ 1 3 1 ]
Final:
[ 1 3 1 ]
[ 1 3 1 ]
Example 2:
Input: $row = 2, $col = 2, @locations = ([1,1],[0,0])
Output: 0
Initial:
[ 0 0 ]
[ 0 0 ]
Apply [1,1]:
Increment row 1:
Before After
[ 0 0 ] [ 0 0 ]
[ 0 0 ] [ 1 1 ]
Increment col 1:
Before After
[ 0 0 ] [ 0 1 ]
[ 1 1 ] [ 1 2 ]
Apply [0,0]:
Increment row 0:
Before After
[ 0 1 ] [ 1 2 ]
[ 1 2 ] [ 1 2 ]
Increment col 0:
Before After
[ 1 2 ] [ 2 2 ]
[ 1 2 ] [ 2 2 ]
Final:
[ 2 2 ]
[ 2 2 ]
Example 3:
Input: $row = 3, $col = 3, @locations = ([0,0],[1,2],[2,1])
Output: 0
Initial:
[ 0 0 0 ]
[ 0 0 0 ]
[ 0 0 0 ]
Apply [0,0]:
Increment row 0:
Before After
[ 0 0 0 ] [ 1 1 1 ]
[ 0 0 0 ] [ 0 0 0 ]
[ 0 0 0 ] [ 0 0 0 ]
Increment col 0:
Before After
[ 1 1 1 ] [ 2 1 1 ]
[ 0 0 0 ] [ 1 0 0 ]
[ 0 0 0 ] [ 1 0 0 ]
Apply [1,2]:
Increment row 1:
Before After
[ 2 1 1 ] [ 2 1 1 ]
[ 1 0 0 ] [ 2 1 1 ]
[ 1 0 0 ] [ 1 0 0 ]
Increment col 2:
Before After
[ 2 1 1 ] [ 2 1 2 ]
[ 2 1 1 ] [ 2 1 2 ]
[ 1 0 0 ] [ 1 0 1 ]
Apply [2,1]:
Increment row 2:
Before After
[ 2 1 2 ] [ 2 1 2 ]
[ 2 1 2 ] [ 2 1 2 ]
[ 1 0 1 ] [ 2 1 2 ]
Increment col 1:
Before After
[ 2 1 2 ] [ 2 2 2 ]
[ 2 1 2 ] [ 2 2 2 ]
[ 2 1 2 ] [ 2 2 2 ]
Final:
[ 2 2 2 ]
[ 2 2 2 ]
[ 2 2 2 ]
Example 4:
Input: $row = 1, $col = 5, @locations = ([0,2],[0,4])
Output: 2
Initial:
[ 0 0 0 0 0 ]
Apply [0,2]:
Increment row 0:
Before After
[ 0 0 0 0 0 ] [ 1 1 1 1 1 ]
Increment col 2:
Before After
[ 1 1 1 1 1 ] [ 1 1 2 1 1 ]
Apply [0,4]:
Increment row 0:
Before After
[ 1 1 2 1 1 ] [ 2 2 3 2 2 ]
Increment col 4:
Before After
[ 2 2 3 2 2 ] [ 2 2 3 2 3 ]
Final:
[ 2 2 3 2 3 ]
Example 5:
Input: $row = 4, $col = 2, @locations = ([1,0],[3,1],[2,0],[0,1])
Output: 8
Initial:
[ 0 0 ]
[ 0 0 ]
[ 0 0 ]
[ 0 0 ]
Apply [1,0]:
Increment row 1:
Before After
[ 0 0 ] [ 0 0 ]
[ 0 0 ] [ 1 1 ]
[ 0 0 ] [ 0 0 ]
[ 0 0 ] [ 0 0 ]
Increment col 0:
Before After
[ 0 0 ] [ 1 0 ]
[ 1 1 ] [ 2 1 ]
[ 0 0 ] [ 1 0 ]
[ 0 0 ] [ 1 0 ]
Apply [3,1]:
Increment row 3:
Before After
[ 1 0 ] [ 1 0 ]
[ 2 1 ] [ 2 1 ]
[ 1 0 ] [ 1 0 ]
[ 1 0 ] [ 2 1 ]
Increment col 1:
Before After
[ 1 0 ] [ 1 1 ]
[ 2 1 ] [ 2 2 ]
[ 1 0 ] [ 1 1 ]
[ 2 1 ] [ 2 2 ]
Apply [2,0]:
Increment row 2:
Before After
[ 1 1 ] [ 1 1 ]
[ 2 2 ] [ 2 2 ]
[ 1 1 ] [ 2 2 ]
[ 2 2 ] [ 2 2 ]
Increment col 0:
Before After
[ 1 1 ] [ 2 1 ]
[ 2 2 ] [ 3 2 ]
[ 2 2 ] [ 3 2 ]
[ 2 2 ] [ 3 2 ]
Apply [0,1]:
Increment row 0:
Before After
[ 2 1 ] [ 3 2 ]
[ 3 2 ] [ 3 2 ]
[ 3 2 ] [ 3 2 ]
[ 3 2 ] [ 3 2 ]
Increment col 1:
Before After
[ 3 2 ] [ 3 3 ]
[ 3 2 ] [ 3 3 ]
[ 3 2 ] [ 3 3 ]
[ 3 2 ] [ 3 3 ]
Final:
[ 3 3 ]
[ 3 3 ]
[ 3 3 ]
[ 3 3 ]
#! /usr/bin/env raku
unit sub MAIN (*@locations where @locations.elems > 0 # [1]
&& all(@locations) ~~ /^\d+\,\d+$/, # [1a]
UInt :r(:$row) where $row > 0, # [2]
UInt :c(:$col) where $col > 0, # [2a]
:v(:$verbose));
my @matrix = [0 xx $col] xx $row; # [3]
say ": Initial matrix: { @matrix.raku }" if $verbose;
for @locations -> $location # [4]
{
my ($r, $c) = $location.split(','); # [5]
die "Row $r is out of scope" if $r > $row; # [6]
die "Col $c is out of scope" if $c > $col; # [6a]
@matrix[$r][$_]++ for ^$col; # [7]
@matrix[$_][$c]++ for ^$row; # [8]
say ": Row: $r, Col: $c -> { @matrix.raku }" if $verbose;
}
say @matrix[*;*].grep( ! ( * %% 2 ) ).elems; # [9]
# 9a ####### # 9b ############### # 9c #
[1] At least one element, and all of them must satisfy the regex; one or more digits a comma and one or more digits.
[2] A named argument for the number of rows [2] and columns [2a].
The Unsigned Integer UInt
type allows zero, so I have added
the where
clause to prevent that.
[3] Prepopulate the matrix with zeroes. This avoids
warnings in [7] and [8] when the initial zero is missing, and makes
printing the matrix (in the two verbose mode lines) easier. We do
this with the list repetition operator xx
. The first one (from
the left) generates a (single) row with the specified number of
columns, and the second one duplicates this to the correct number of
rows.
See docs.raku.org/routine/xx for more information about xx
.
[4] Iterate over the locations.
[5] Extract the row and column numbers.
[6] Die if we are outside the matrix.
[7] Add 1 to the whole row,
[8] and the whole column. Note that the location will be increased twice.
[9] Flatten the matrix [9a] and extract the values that are odd (not divisible by 2) [9b], count them [9c] and print the result.
Running it:
$ ./odd-matrix -r=2 -c=3 0,1 1,1
6
$ ./odd-matrix -r=2 -c=2 1,1 0,0
0
$ ./odd-matrix -r=3 -c=3 0,0 1,2 2,1
0
$ ./odd-matrix -r=1 -c=5 0,1 0,4
2
$ ./odd-matrix -r=4 -c=2 1,0 3,1 2,0 0,1
8
Looking good.
With verbose mode:
$ ./odd-matrix -v -r=2 -c=3 0,1 1,1
: Initial matrix: [[0, 0, 0], [0, 0, 0]]
: Row: 0, Col: 1 -> [[1, 2, 1], [0, 1, 0]]
: Row: 1, Col: 1 -> [[1, 3, 1], [1, 3, 1]]
6
$ ./odd-matrix -v -r=2 -c=2 1,1 0,0
: Initial matrix: [[0, 0], [0, 0]]
: Row: 1, Col: 1 -> [[0, 1], [1, 2]]
: Row: 0, Col: 0 -> [[2, 2], [2, 2]]
0
$ ./odd-matrix -v -r=3 -c=3 0,0 1,2 2,1
: Initial matrix: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
: Row: 0, Col: 0 -> [[2, 1, 1], [1, 0, 0], [1, 0, 0]]
: Row: 1, Col: 2 -> [[2, 1, 2], [2, 1, 2], [1, 0, 1]]
: Row: 2, Col: 1 -> [[2, 2, 2], [2, 2, 2], [2, 2, 2]]
0
$ ./odd-matrix -v -r=1 -c=5 0,1 0,4
: Initial matrix: [[0, 0, 0, 0, 0],]
: Row: 0, Col: 1 -> [[1, 2, 1, 1, 1],]
: Row: 0, Col: 4 -> [[2, 3, 2, 2, 3],]
2
$ ./odd-matrix -v -r=4 -c=2 1,0 3,1 2,0 0,1
: Initial matrix: [[0, 0], [0, 0], [0, 0], [0, 0]]
: Row: 1, Col: 0 -> [[1, 0], [2, 1], [1, 0], [1, 0]]
: Row: 3, Col: 1 -> [[1, 1], [2, 2], [1, 1], [2, 2]]
: Row: 2, Col: 0 -> [[2, 1], [3, 2], [3, 2], [3, 2]]
: Row: 0, Col: 1 -> [[3, 3], [3, 3], [3, 3], [3, 3]]
8
Verbose mode printed the matrices as oneliners. That is not especially readable. Here is a procedure doing a better job:
sub pretty-print-matrtix(@matrix)
{
say "[";
for @matrix -> @row { say " [{ @row.join(", ") }]" };
say "]";
}
Just saying...
And that's it.