Oddly Current
with Raku

by Arne Sommer

Oddly Current with Raku

[361] Published 3. September 2025.

This is my response to The Weekly Challenge #337.

Challenge #337.1: Smaller Than Current

You are given an array of numbers, @num1.

Write a script to return an array, @num2, where $num2[i] is the count of all numbers less than or equal to $num1[i].

Example 1:
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.

Challenge #337.2:

You are given row and col, also a list of positions in the matrix.

Write a script to perform action on each location (0-indexed) as provided in the list and find out the total odd valued cells.

For each location (r, c), do both of the following:
  1. Increment by 1 all the cells on row r
  2. Increment by 1 all the cells on column c
Example 1:
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 ]
File: odd-matrix
#! /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.