with Raku

This is my response to The Weekly Challenge #251.

You are given an array of integers,

Write a script to find the concatenation value of the given array.

The concatenation of two numbers is the number formed by concatenating their numerals.

`@ints`

.
Write a script to find the concatenation value of the given array.

The concatenation of two numbers is the number formed by concatenating their numerals.

For example, the concatenation of 10, 21 is 1021.
The concatenation value of @ints is initially equal to 0.
Perform this operation until @ints becomes empty:
If there exists more than one number in @ints, pick the first element
and last element in @ints respectively and add the value of their
concatenation to the concatenation value of @ints, then delete the
first and last element from @ints.
If one element exists, add its value to the concatenation value of
@ints, then delete it.

Example 1:
Input: @ints = (6, 12, 25, 1)
Output: 1286
1st operation: concatenation of 6 and 1 is 61
2nd operation: concaternation of 12 and 25 is 1225
Concatenation Value => 61 + 1225 => 1286

Example 2:
Input: @ints = (10, 7, 31, 5, 2, 2)
Output: 489
1st operation: concatenation of 10 and 2 is 102
2nd operation: concatenation of 7 and 2 is 72
3rd operation: concatenation of 31 and 5 is 315
Concatenation Value => 102 + 72 + 315 => 489

Example 3:
Input: @ints = (1, 2, 10)
Output: 112
1st operation: concatenation of 1 and 10 is 110
2nd operation: only element left is 2
Concatenation Value => 110 + 2 => 112

Note that integers does not work so well in
practice, so I have used the more restrictive `UInt`

(Unsigned Integer)
type.as e.g. `12`

and `-5`

would not add up to any good (i.e. the
string `"12-5"`

).

See docs.raku.org/type/UInt for more information about the `UInt`

type.

#! /usr/bin/env raku
unit sub MAIN (*@ints where all(@ints) ~~ UInt && @ints.elems > 0, # [1]
:v(:$verbose));
my $output = 0; # [2]
say ":Remaining:{ @ints.join(",") }" if $verbose;
while @ints # [3]
{
my $add = @ints.shift; # [4]
$add ~= @ints.pop if @ints.elems; # [5]
$output += $add; # [6]
say ":Remaining:{ @ints.join(",") } - Add:$add (Total:$output)" if $verbose;
}
say $output; # [7]

[1] At least one element, and they must all be non-negative integers.

[2] The result will end up here.

[3] As long as we have unfinished business.

[4] Get the leftmost value with `shift`

.

See docs.raku.org/routine/shift for more information about `shift`

.

[5] Get the rightmost value with `pop`

, if it exists, and
concatenate it with the one we got in [4].

See docs.raku.org/routine/pop for more information about `pop`

.

[6] Add the sum to the total.

[7] Print the result.

Running it:

$ ./concatenation-value 6 12 25 1
1286
$ ./concatenation-value 10 7 31 5 2 2
489
$ ./concatenation-value 1 2 10
112

Looking good.

With verbose mode:

$ ./concatenation-value -v 6 12 25 1
:Remaining:6,12,25,1
:Remaining:12,25 - Add:61 (Total:61)
:Remaining: - Add:1225 (Total:1286)
1286
$ ./concatenation-value -v 10 7 31 5 2 2
:Remaining:10,7,31,5,2,2
:Remaining:7,31,5,2 - Add:102 (Total:102)
:Remaining:31,5 - Add:72 (Total:174)
:Remaining: - Add:315 (Total:489)
489
$ ./concatenation-value -v 1 2 10
:Remaining:1,2,10
:Remaining:2 - Add:110 (Total:110)
:Remaining: - Add:2 (Total:112)
112

You are given a

Write a script to return the lucky number, if there is one, or -1 if not.

A lucky number is an element of the matrix such that it is the minimum element in its row and maximum in its column.

Example 1:

`m x n`

matrix of distinct numbers.
Write a script to return the lucky number, if there is one, or -1 if not.

A lucky number is an element of the matrix such that it is the minimum element in its row and maximum in its column.

Example 1:

Input: $matrix = [ [ 3, 7, 8],
[ 9, 11, 13],
[15, 16, 17] ];
Output: 15
15 is the only lucky number since it is the minimum in its row
and the maximum in its column.

Example 2:
Input: $matrix = [ [ 1, 10, 4, 2],
[ 9, 3, 8, 7],
[15, 16, 17, 12] ];
Output: 12

Example 3:
Input: $matrix = [ [7 ,8],
[1 ,2] ];
Output: 7

Specifying a matrix on the command line was last done in Challenge #248.2: Submatrix Sum. In exactly the same way.

File: lucky-numbers#! /usr/bin/env raku
unit sub MAIN (Str $matrix = "3 7 8 | 9 11 13 | 15 16 17", # [1]
:v(:$verbose));
my @a = $matrix.split("|")>>.words>>.Int>>.Array; # [2]
my $rows = @a.elems; # [3]
my $cols = @a[0].elems; # [4]
my @values = @a[*;*]; # [5]
die "The rows must have the same size" unless [==] @a>>.elems; # [6]
die "Integers only" unless all(@values) ~~ Int; # [7]
die "Unique values only" unless @values.elems == @values.unique.elems; # [8]
say ":Matrix: { @a.raku }" if $verbose;
for 0 .. $rows -1 -> $row # [9]
{
my @row = |@a[$row]; # [10]
my ($col, $min) = @row.minpairs.first.kv; # [11]
say ":Row[$row]: { @row.join(",") } - lowest:$min (at column:$col)"
if $verbose;
my @col = @a[*;$col]; # [12]
my $max = @col.max; # [13]
say ":- Col[$col]: { @col.join(",") } - highest:$max" if $verbose;
if $max == $min # [14]
{
say $max; # [14a]
exit; # [14b]
}
}
say "-1"; # [15]

[1] The default matrix shows how to specify one on the command line.

[2] Get a two dimentional array (also known as a matrix). The
values are coerced (from strings, courtesy of `words`

) to integers to
catch non-numeric input. (Note that non-integer numeric values will be
coerced to integers.)

See docs.raku.org/routine/words for more information about `words`

.

[3] The number of rows.

[4] The number of columns, in the first (index zero) row.

[5] All the values, as a one dimentional array.

[6] Ensure that all the rows have the same number of elements.

[7] Ensure integers only.

[8] Ensure unique values only.

[9] Iterate over the row indices.

[10] Get the row data, and flatten it (with `|`

) to a one-dimentional
array.

[11]
`minpairs`

will give a list of the lowest value, as
pair objects; the first part is the index and the second the actual value. This
is a list, as duplicates of this lowest value obviously will have different
indices. The values are unique (courtesy of [8]), so can only get one pair
object here. But it is still a list, so we get the first (and only) element
with `first`

. Finally we split out the key and value with `kv`

.

See docs.raku.org/routine/minpairs for more information about `minpairs`

.

See docs.raku.org/routine/first for more information about `first`

.

See docs.raku.org/routine/kv for more information about `kv`

.

[12] Get the column values. Note the syntax.

[13] Get the maximum value.

[14] Is the minimum (row) identical with the maximum (column)? If
so, print the value and exit. (Note that we can compare the values, so can happily
skip the `maxpairs`

that we would deduce from the row (in [10]).

See docs.raku.org/routine/maxpairs for more information about `maxpairs`

.

[15] Not found. Say so.

Running it:

$ ./lucky-numbers
15
$ ./lucky-numbers "1 10 4 2 | 9 3 8 7 | 15 16 17 12"
12
$ ./lucky-numbers "7 8 | 1 2"
7

Looking good.

With verbose mode:

$ ./lucky-numbers -v
:Matrix: [[3, 7, 8], [9, 11, 13], [15, 16, 17]]
:Row[0]: 3,7,8 - lowest:3 (at column:0)
:- Col[0]: 3,9,15 - highest:15
:Row[1]: 9,11,13 - lowest:9 (at column:0)
:- Col[0]: 3,9,15 - highest:15
:Row[2]: 15,16,17 - lowest:15 (at column:0)
:- Col[0]: 3,9,15 - highest:15
15
$ ./lucky-numbers -v "1 10 4 2 | 9 3 8 7 | 15 16 17 12"
:Matrix: [[1, 10, 4, 2], [9, 3, 8, 7], [15, 16, 17, 12]]
:Row[0]: 1,10,4,2 - lowest:1 (at column:0)
:- Col[0]: 1,9,15 - highest:15
:Row[1]: 9,3,8,7 - lowest:3 (at column:1)
:- Col[1]: 10,3,16 - highest:16
:Row[2]: 15,16,17,12 - lowest:12 (at column:3)
:- Col[3]: 2,7,12 - highest:12
12
$ ./lucky-numbers -v "7 8 | 1 2"
:Matrix: [[7, 8], [1, 2]]
:Row[0]: 7,8 - lowest:7 (at column:0)
:- Col[0]: 7,1 - highest:7
7

And that's it.