Lucky Concatenation
with Raku

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.

[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.