This is my response to The Weekly Challenge #266.
$line1
and $line2
.
('')
if none found.
Input: $line1 = 'Mango is sweet'
$line2 = 'Mango is sour'
Output: ('sweet', 'sour')
Example 2:
Input: $line1 = 'Mango Mango'
$line2 = 'Orange'
Output: ('Orange')
Example 3:
Input: $line1 = 'Mango is Mango'
$line2 = 'Orange is Orange'
Output: ('')
Why restrict ourselves to just two lines, when we can have as many as we want - with a slurpy array?
File: uncommon-words
#! /usr/bin/env raku
unit sub MAIN (*@lines where @lines.elems > 1, :v(:$verbose)); # [1]
my $bag = Bag.new; # [2]
for @lines -> $line # [3]
{
my @words = $line.words; # [4]
$bag (+)= @words; # [5]
say ": Bag: { $bag.raku }" if $verbose;
}
say '(' ~ $bag.grep({ $_.value == 1 }).map({ "'" ~ $_.key ~ "'" })
.join(", ") ~ ')'; # [6}
[1] Two or more lines.
[2] Set up an empty Bag
, to collect the letters
from the words.
See docs.raku.org/routine/Bag for more information about Bag
.
[3] Iterate over the lines.
[4] Turn the current line into words (with words
).
[5] Add the words to the Bag, where (+)=
is the assign
back version of (+)
.
[6] Pretty print the result, starting with grep
to filter out
entries with a frequency of 1, then a map
to print the key wrapped
in quotes, and finally a join
to get a comma separated string.
Running it:
$ ./uncommon-words 'Mango is sweet' 'Mango is sour'
('sour', 'sweet')
$ ./uncommon-words 'Mango Mango' 'Orange'
('Orange')
$ ./uncommon-words 'Mango is Mango' 'Orange is Orange'
()
Looking good.
Note that the word order is random:
$ ./uncommon-words 'Mango is sweet' 'Mango is sour'
('sweet', 'sour')
$ ./uncommon-words 'Mango is sweet' 'Mango is sour'
('sour', 'sweet')
We could have fixed that by insering a sort
before the grep
, but
the order would not be the same as specifed in the input - which would most
likely be considered the correct order. I'll leave that up to the
readers...
With verbose mode:
$ ./uncommon-words -v 'Mango is sweet' 'Mango is sour'
: Bag: ("Mango"=>1,"sweet"=>1,"is"=>1).Bag
: Bag: ("sour"=>1,"Mango"=>2,"sweet"=>1,"is"=>2).Bag
('sour', 'sweet')
$ ./uncommon-words -v 'Mango Mango' 'Orange'
: Bag: ("Mango"=>2).Bag
: Bag: ("Mango"=>2,"Orange"=>1).Bag
('Orange')
$ ./uncommon-words -v 'Mango is Mango' 'Orange is Orange'
: Bag: ("Mango"=>2,"is"=>1).Bag
: Bag: ("Mango"=>2,"is"=>2,"Orange"=>2).Bag
()
$matrix
.
X Matrix
.
Input: $matrix = [ [1, 0, 0, 2],
[0, 3, 4, 0],
[0, 5, 6, 0],
[7, 0, 0, 1],
]
Output: true
Example 2:
Input: $matrix = [ [1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
Output: false
Example 3:
Input: $matrix = [ [1, 0, 2],
[0, 3, 0],
[4, 0, 5],
]
Output: true
The «matrix on the command line» code has been copied from e.g. Currently Reduced with Raku; Challenge #257.2: Reduced Row Echelon.
File: x-matrix
#! /usr/bin/env raku
unit sub MAIN ($string = "1 0 0 2 | 0 3 4 0 | 0 5 6 0 | 7 0 0 1", # [1]
:v(:$verbose));
my $matrix = $string.split("|")>>.words>>.Int>>.Array; # [2]
die "The rows must have the same size" unless [==] $matrix>>.elems; # [3]
die "The number of rows and columns are not the same"
unless $matrix.elems == $matrix[0].elems; # [4]
my $size = $matrix.elems; # [5]
for ^$size -> $row # [6]
{
for ^$size -> $col # [7]
{
my $is-on-x = on-the-x(:$row, :$col, :$size); # [8]
my $value = $matrix[$row][$col]; # [9]
my $ok = $is-on-x ?? $value != 0 !! $value == 0; # [10]
say ": [$row,$col]: $value { $is-on-x ?? "X" !! "-" } \
{ $ok ?? "ok" !! "error" }";
unless $ok # [11]
{
say 'false'; # [11a]
exit; # [11b]
}
}
}
say 'true'; # [12]
sub on-the-x (:$row, :$col, :$size) # [13]
{
my $last-index = $size -1; # [14]
return True if $row == $col; # [15]
return True if $last-index - $row == $col; # [16]
return False; # [17]
}
[1] Note the default matrix.
[2] Turn the matrix string into a two dimentional array (of integers).
Note that >>.Int
makes it legal to specify e.g. «3.14»,
which will be truncated to «3».
[3] All the rows must have the same size.
[4] The number of rows and columns must be the same.
[5] The matrix size, as we are going to use it multiple times.
[6] Iterate over the row indices (from 0 to one less than the size).
[7] Iterate over the column indices.
[8] Is the current position on the X (i.e. on the main diagonal or antidiagonal)? Note the named argument syntax (the leading colon).
[9] Get the value at the current position.
[10] All is well if we have a non-zero value on the X, and zero otherwise.
[11] Not ok? Say so [11a] and exit [11b].
[12] Not falsified? Then we have succeeded. Say so.
[13] Note the three named arguments.
[14] Calculate the last index.
[15] Success if we are on the main diagonal.
[16] Success if we are on the antidiagonal.
[17] Failure otherwise.
Running it:
$ ./x-matrix
true
$ ./x-matrix "1 2 3 | 4 5 6 | 7 8 9"
false
$ ./x-matrix "1 0 2 | 0 3 0 | 4 0 5"
true
Looking good.
With verbose mode:
$ ./x-matrix -v
: [0,0]: 1 X ok
: [0,1]: 0 - ok
: [0,2]: 0 - ok
: [0,3]: 2 X ok
: [1,0]: 0 - ok
: [1,1]: 3 X ok
: [1,2]: 4 X ok
: [1,3]: 0 - ok
: [2,0]: 0 - ok
: [2,1]: 5 X ok
: [2,2]: 6 X ok
: [2,3]: 0 - ok
: [3,0]: 7 X ok
: [3,1]: 0 - ok
: [3,2]: 0 - ok
: [3,3]: 1 X ok
true
$ ./x-matrix -v "1 2 3 | 4 5 6 | 7 8 9"
: [0,0]: 1 X ok
: [0,1]: 2 - error
false
$ ./x-matrix -v "1 0 2 | 0 3 0 | 4 0 5"
: [0,0]: 1 X ok
: [0,1]: 0 - ok
: [0,2]: 2 X ok
: [1,0]: 0 - ok
: [1,1]: 3 X ok
: [1,2]: 0 - ok
: [2,0]: 4 X ok
: [2,1]: 0 - ok
: [2,2]: 5 X ok
true
And that's it.