Tonight’s musical mood: Luck Be A Lady!
Onward to Perl Weekly Challenge 251!
Task 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: concatenation 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
Approach
I know there’s an iterative approach that’s probably more efficient, but when I saw the definition of how to do calculate the concatenation value of an array of integers, my brain flew back to being a 15-year-old learning how to program, and discovering the wonders of… recursion.
Edit: It occurs to me that seeing Niklaus Wirth’ obituary probably also inspired me, because part and parcel of my discovering recursion when I was 15 was learning Pascal, my favorite programming language before Perl (also the second or third (I don’t remember if it was BASIC, Pascal, then COBOL, or BASIC, COBOL, then Pascal)).
Raku
sub concatenationValue(@ints) {
return 0 if @ints.elems == 0; # no elements
return @ints[0] if @ints.elems == 1; # one element
my $first = @ints.shift; # first element
my $last = @ints.pop; # last element
my $concat = "$first$last".Int; # concatenate and convert
return $concat + concatenationValue(@ints);
}
View the entire Raku script for this task on GitHub.
Perl
Once again I got to trot out the “adding 0 to a string to make it clear I’m converting it into a numeric value” trick, and I also got to show how evaluating an array in scalar context (the @ints == 0
and @ints == 1
) yields the number of elements in the array.
sub concatenationValue(@ints) {
return 0 if @ints == 0; # no elements
return $ints[0] if @ints == 1; # one element
my $first = shift @ints; # first element
my $last = pop @ints; # last element
my $concat = "$first$last"+0; # concatenate and convert
return $concat + concatenationValue(@ints);
}
View the entire Perl script for this task on GitHub.
Python
The only thing to point out here is Python’s pop method, which removes the element at the position specified by the parameter. If the parameter is omitted, it removes and returns the last value in the array, but since I had to specify position 0
to get the first element, I figured it was symmetrical to specify -1
to explicitly get the last value.
def concatenationValue(ints):
if len(ints) == 0: # no elements
return 0
if len(ints) == 1: # one element
return ints[0]
first = ints.pop(0); # first element
last = ints.pop(-1); # last element
concat = int(f"{first}{last}") # concatenate and convert
return concat + concatenationValue(ints)
View the entire Python script for this task on GitHub.
Task 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
Approach
Since the definition of the problem states that the numbers are distinct (the same number will not appear twice in the matrix), we can break this down into two problems: find the minimum elements in each row, and find the maximum elements in each column. If a value appears in both lists, we have our lucky number.
Getting the minimum in each row is easy, but getting the max in each column is a little more work; what I’m going to do is rotate the matrix so the rows are now columns and the columns are now rows, and just take the max value from what are now rows in the matrix.
Raku
sub maxCols(@matrix) {
my @rotated; # rotate cols to rows
for @matrix -> @row {
for @row.kv -> $k, $v {
@rotated[$k].push($v);
}
}
# return the max of the now rows!
return @rotated.map({ $_.max() });
}
sub luckyNumber(@matrix) {
my @minRows = @matrix.map({ $_.min() });
my @maxCols = maxCols(@matrix);
return ( @minRows (&) @maxCols ) // -1;
}
View the entire Raku script for this task on GitHub.
Perl
Perl doesn’t have built-in min, max, or intersection operators, so we need to pull them in from the CPAN modules Array::Utils
and List::Util
(though List::Util
is in the core).
use Array::Utils qw( intersect );
use List::Util qw( min max );
sub maxCols(@matrix) {
my @rotated; # rotate cols to rows
foreach my $row ( @matrix ) {
foreach my $k ( 0 .. $#{$row} ) {
my $v = $row->[$k];
push @{$rotated[$k]}, $v;
}
}
# return the max of the now rows!
return map { max( @$_ ) } @rotated;
}
sub luckyNumber(@matrix) {
my @minRows = map { min( @$_ ) } @matrix;
my @maxCols = maxCols(@matrix);
# intersect() returns an array, so get the first element
return (intersect( @minRows, @maxCols ))[0] // -1;
View the entire Perl script for this task on GitHub.
Python
For my Python solution, I was able to do it entirely using built-in functions.
def maxCols(matrix):
# initialize rotated with empty row for each column
rotated = [ [] for col in matrix[0] ]
for row in matrix:
for k, v in enumerate(row):
rotated[k].append(v)
# return the max of the now rows!
return [ max(row) for row in rotated ]
def luckyNumber(matrix):
mRows = [ min(row) for row in matrix ]
mCols = maxCols(matrix)
intersection = list( set(mRows) & set(mCols) )
if intersection:
return intersection[0]
else:
return -1
View the entire Python script for this task on GitHub.
Here’s all my solutions in GItHub: https://github.com/packy/perlweeklychallenge-club/tree/master/challenge-251/packy-anderson