Weakest Split
with Raku

by Arne Sommer

Weakest Split with Raku

[273] Published 23. January 2024.

This is my response to The Weekly Challenge #253.

Challenge #253.1: Split Strings

You are given an array of strings and a character separator.

Write a script to return all words separated by the given character excluding empty string.

Example 1:
Input: @words = ("one.two.three","four.five","six")
       $separator = "."
Output: "one","two","three","four","five","six"
Example 2:
Input: @words = ("$perl$$", "$$raku$")
       $separator = "$"
Output: "perl","raku"
File: split-strings
#! /usr/bin/env raku

unit sub MAIN ($separator where $separator.chars == 1,
               *@words where @words.elems > 0);

say @words>>.split($separator).[*;*].grep( *.chars ).map( '"' ~ * ~ '"' ).join(",");

[unit] First a (single) separator character on the command line, followed by a slurpy array of (one or more) words.

[say] Split each word (with >>.split($separator)) on the separator. This gives us a two dimentional array, which we flatten with [*;*]. Then we use grep( *.chars ) to get rid of empty words (i.e. without length), and map( '"' ~ * ~ '"' ) to wrap each word in quotes. Finally we apply join(",") to get a comma separated string of words.

Running it:

$ ./split-strings "." "one.two.three" "four.five" "six"
"one","two","three","four","five","six"

$ ./split-strings "$" "$perl$$" "$$raku$"
"8169","8169raku"

Ooops.

The Shell replaces $$ with the process ID of the shell itself. Using single quotes instead of double quotes will prevent this replacement.

$ ./split-strings '$' '$perl$$' '$$raku$'
"perl","raku"

Challenge #253.2: Weakest Row

You are given an m x n binary matrix i.e. only 0 and 1 where 1 always appear before 0.

A row i is weaker than a row j if one of the following is true:
  1. The number of 1s in row i is less than the number of 1s in row j
  2. Both rows have the same number of 1 and i < j
Write a script to return the order of rows from weakest to strongest.

Example 1:
Input: $matrix = [
                   [1, 1, 0, 0, 0],
                   [1, 1, 1, 1, 0],
                   [1, 0, 0, 0, 0],
                   [1, 1, 0, 0, 0],
                   [1, 1, 1, 1, 1]
                 ]
Output: (2, 0, 3, 1, 4)

The number of 1s in each row is:
- Row 0: 2
- Row 1: 4
- Row 2: 1
- Row 3: 2
- Row 4: 5
Example 2:
Input: $matrix = [
                   [1, 0, 0, 0],
                   [1, 1, 1, 1],
                   [1, 0, 0, 0],
                   [1, 0, 0, 0]
                 ]
Output: (0, 2, 3, 1)

The number of 1s in each row is:
- Row 0: 1
- Row 1: 4
- Row 2: 1
- Row 3: 1

File: weakest-row
#! /usr/bin/env raku

unit sub MAIN ($string = "1 0 0 0 | 1 1 1 1  | 1 0 0 0 | 1 0 0 0",  # [1]
               :v(:$verbose));

my $matrix = $string.split("|")>>.words>>.Int>>.Array;              # [2]
my @values = $matrix[*;*];                                          # [3]

die "The rows must have the same size" unless [==] $matrix>>.elems; # [4]
die "0 and 1 only" unless all(@values) ~~ any(0,1);                 # [5]
die "1 before 0 only" unless $matrix>>.reduce( &infix:«>=» );       # [6]

my @pairs  = $matrix>>.sum.pairs;                                   # [7]
my @sorted = @pairs.sort({ $^a.value <=> $^b.value || $^a.key <=> $^b.key });
                                                                    # [8]
say ":Pairs:  { @pairs.raku }"  if $verbose;
say ":Sorted: { @sorted.raku }" if $verbose;

say "({ @sorted>>.key.join(", ") })";                               # [9]

[1] Note the default matrix. The matrix parsing code was last seen two weeks ago; Lucky Concatenation with Raku (scroll down to #251.2 Lucky Numbers).

[2] Get the matrix (a two dimentional array).

[3] Get the values (a one dimentional array).

[4] The rows in the matrix must have the same size.

[5] The matrix can only contain zeroes and ones.

[6] For each row, ensure that the values from the left are larger than or equal to the next one.

[7] Get the sum (i.e. the number of ones) for each row, and turn those sums into Pair objects with pairs - with the index as key, and the sum as value.

See docs.raku.org/routine/pairs for more information about pairs.

[8] Sort the array, using the values (the number of ones), and secondary the row number (the former array index).

[9] Print the key part (the row index) of the pairs.

Running it:

$ ./weakest-row "1 1 0 0 0 | 1 1 1 1 0 | 1 0 0 0 0 | 1 1 0 0 0 | 1 1 1 1 1"
(2, 0, 3, 1, 4)

$ ./weakest-row
(0, 2, 3, 1)

Looking good.

With verbose mode:

$ ./weakest-row -v "1 1 0 0 0 | 1 1 1 1 0 | 1 0 0 0 0 | 1 1 0 0 0 | 1 1 1 1 1"
:Pairs:  [0 => 2, 1 => 4, 2 => 1, 3 => 2, 4 => 5]
:Sorted: [2 => 1, 0 => 2, 3 => 2, 1 => 4, 4 => 5]
(2, 0, 3, 1, 4)

$ ./weakest-row -v
:Pairs:  [0 => 1, 1 => 4, 2 => 1, 3 => 1]
:Sorted: [0 => 1, 2 => 1, 3 => 1, 1 => 4]
(0, 2, 3, 1)

And that's it.