by Arne Sommer

Lucky Concatenation with Raku

[271] Published 9. January 2024.

This is my response to The Weekly Challenge #251.

Challenge #251.1: Concatenation Value

You are given an array of integers, `@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.

File: concatenation-value ```#! /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 ```

Challenge #251.2: Lucky Numbers

You are given a `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`.

```\$ ./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 ```
```\$ ./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 ```