Perl Weekly Challenge 338: “Highest Row” and “Max Distance”…
Let’s have some fun!
Task 1: Highest Row
You are given a m x n
matrix.
Write a script to find the highest row sum in the given matrix.
Example 1
Input: @matrix = ([4, 4, 4, 4],
[10, 0, 0, 0],
[2, 2, 2, 9])
Output: 16
Row 1: 4 + 4 + 4 + 4 => 16
Row 2: 10 + 0 + 0 + 0 => 10
Row 3: 2 + 2 + 2 + 9 => 15
Example 2
Input: @matrix = ([1, 5],
[7, 3],
[3, 5])
Output: 10
Example 3
Input: @matrix = ([1, 2, 3],
[3, 2, 1])
Output: 6
Example 4
Input: @matrix = ([2, 8, 7],
[7, 1, 3],
[1, 9, 5])
Output: 17
Example 5
Input: @matrix = ([10, 20, 30],
[5, 5, 5],
[0, 100, 0],
[25, 25, 25])
Output: 100
Approach
This is essentially a two-step matrix reduction: first we find the sums of each of the rows, then we get the maximum value for these sums.
Raku
In Raku, we can get this down to one line:
sub highestRow(@matrix) {
@matrix.map({ $_.sum }).max
}
View the entire Raku script for this task on GitHub.
$ raku/ch-1.raku
Example 1:
Input: @matrix = ([4, 4, 4, 4],
[10, 0, 0, 0],
[2, 2, 2, 9])
Output: 16
Example 2:
Input: @matrix = ([1, 5],
[7, 3],
[3, 5])
Output: 10
Example 3:
Input: @matrix = ([1, 2, 3],
[3, 2, 1])
Output: 6
Example 4:
Input: @matrix = ([2, 8, 7],
[7, 1, 3],
[1, 9, 5])
Output: 17
Example 5:
Input: @matrix = ([10, 20, 30],
[5, 5, 5],
[0, 100, 0],
[25, 25, 25])
Output: 100
Perl
In Perl, we need to import max
and sum
from a CPAN module, and I like List::AllUtils.
use List::AllUtils qw( max sum );
sub highestRow($matrix) {
max map { sum @$_ } @$matrix;
}
View the entire Perl script for this task on GitHub.
Python
In Python, we need to use a list comprehension instead of map
.
def highest_row(matrix):
return max( [ sum(row) for row in matrix ] )
View the entire Python script for this task on GitHub.
Elixir
In Elixir, we just use Enum.map/2
to sum the rows, and pipe that through Enum.max/3
.
def highest_row(matrix) do
Enum.map(matrix, fn row -> Enum.sum(row) end) |> Enum.max
end
View the entire Elixir script for this task on GitHub.
Task 2: Max Distance
You are given two integer arrays, @arr1
and @arr2
.
Write a script to find the maximum difference between any pair of values from both arrays.
Example 1
Input: @arr1 = (4, 5, 7)
@arr2 = (9, 1, 3, 4)
Output: 6
With element $arr1[0] = 4
| 4 - 9 | = 5
| 4 - 1 | = 3
| 4 - 3 | = 1
| 4 - 4 | = 0
max distance = 5
With element $arr1[1] = 5
| 5 - 9 | = 4
| 5 - 1 | = 4
| 5 - 3 | = 2
| 5 - 4 | = 1
max distance = 4
With element $arr1[2] = 7
| 7 - 9 | = 2
| 7 - 1 | = 6
| 7 - 3 | = 4
| 7 - 4 | = 4
max distance = 6
max (5, 6, 6) = 6
Example 2
Input: @arr1 = (2, 3, 5, 4)
@arr2 = (3, 2, 5, 5, 8, 7)
Output: 6
With element $arr1[0] = 2
| 2 - 3 | = 1
| 2 - 2 | = 0
| 2 - 5 | = 3
| 2 - 5 | = 3
| 2 - 8 | = 6
| 2 - 7 | = 5
max distance = 6
With element $arr1[1] = 3
| 3 - 3 | = 0
| 3 - 2 | = 1
| 3 - 5 | = 2
| 3 - 5 | = 2
| 3 - 8 | = 5
| 3 - 7 | = 4
max distance = 5
With element $arr1[2] = 5
| 5 - 3 | = 2
| 5 - 2 | = 3
| 5 - 5 | = 0
| 5 - 5 | = 0
| 5 - 8 | = 3
| 5 - 7 | = 2
max distance = 3
With element $arr1[3] = 4
| 4 - 3 | = 1
| 4 - 2 | = 2
| 4 - 5 | = 1
| 4 - 5 | = 1
| 4 - 8 | = 4
| 4 - 7 | = 3
max distance = 4
max (5, 6, 3, 4) = 6
Example 3
Input: @arr1 = (2, 1, 11, 3)
@arr2 = (2, 5, 10, 2)
Output: 9
With element $arr1[0] = 2
| 2 - 2 | = 0
| 2 - 5 | = 3
| 2 - 10 | = 8
| 2 - 2 | = 0
max distance = 8
With element $arr1[1] = 1
| 1 - 2 | = 1
| 1 - 5 | = 4
| 1 - 10 | = 9
| 1 - 2 | = 1
max distance = 9
With element $arr1[2] = 11
| 11 - 2 | = 9
| 11 - 5 | = 6
| 11 - 10 | = 1
| 11 - 2 | = 9
max distance = 9
With element $arr1[3] = 3
| 3 - 2 | = 1
| 3 - 5 | = 2
| 3 - 10 | = 7
| 3 - 2 | = 1
max distance = 7
max (8, 9, 9, 7) = 9
Example 4
Input: @arr1 = (1, 2, 3)
@arr2 = (3, 2, 1)
Output: 2
With element $arr1[0] = 1
| 1 - 3 | = 2
| 1 - 2 | = 1
| 1 - 1 | = 0
max distance = 2
With element $arr1[1] = 2
| 2 - 3 | = 1
| 2 - 2 | = 0
| 2 - 1 | = 1
max distance = 1
With element $arr1[2] = 3
| 3 - 3 | = 0
| 3 - 2 | = 1
| 3 - 1 | = 2
max distance = 2
max (2, 1, 2) = 2
Example 5
Input: @arr1 = (1, 0, 2, 3)
@arr2 = (5, 0)
Output: 5
With element $arr1[0] = 1
| 1 - 5 | = 4
| 1 - 0 | = 1
max distance = 4
With element $arr1[1] = 0
| 0 - 5 | = 5
| 0 - 0 | = 0
max distance = 5
With element $arr1[2] = 2
| 2 - 5 | = 3
| 2 - 0 | = 2
max distance = 3
With element $arr1[3] = 3
| 3 - 5 | = 2
| 3 - 0 | = 3
max distance = 3
max (4, 5, 3, 3) = 5
Approach
I am not going to present the explanatory text from the examples this time, because it will bloat the solution. Since the pair of values with the max distance has to take one value from each list, the max distance will come from only one of two pairings: |max(@arr1) - min($arr2)|
or |max(@arr2) - min(@arr2)|
.
Raku
And this is all accomplished in Raku through the min
, max
, and abs
.
sub maxDistance(@arr1, @arr2) {
my ($min1, $max1) = (@arr1.min, @arr1.max);
my ($min2, $max2) = (@arr2.min, @arr2.max);
max(abs($max1 - $min2), abs($max2 - $min1));
}
View the entire Raku script for this task on GitHub.
$ raku/ch-2.raku
Example 1:
Input: @arr1 = (4, 5, 7)
@arr2 = (9, 1, 3, 4)
Output: 6
Example 2:
Input: @arr1 = (2, 3, 5, 4)
@arr2 = (3, 2, 5, 5, 8, 7)
Output: 6
Example 3:
Input: @arr1 = (2, 1, 11, 3)
@arr2 = (2, 5, 10, 2)
Output: 9
Example 4:
Input: @arr1 = (1, 2, 3)
@arr2 = (3, 2, 1)
Output: 2
Example 5:
Input: @arr1 = (1, 0, 2, 3)
@arr2 = (5, 0)
Output: 5
Perl
Perl does the same thing, but we need to import min
and max
from a CPAN module, and I like List::AllUtils.
use List::AllUtils qw( min max );
sub maxDistance($arr1, $arr2) {
my ($min1, $max1) = (min(@$arr1), max(@$arr1));
my ($min2, $max2) = (min(@$arr2), max(@$arr2));
max(abs($max1 - $min2), abs($max2 - $min1));
}
View the entire Perl script for this task on GitHub.
Python
Python doesn’t need to pull in any libraries.
def max_distance(arr1, arr2):
(min1, max1) = (min(arr1), max(arr1))
(min2, max2) = (min(arr2), max(arr2))
return max(abs(max1 - min2), abs(max2 - min1))
View the entire Python script for this task on GitHub.
Elixir
I need to pay attention! When I first whipped up the Elixir solution, line 7 looked like this:
Enum.max(abs(max1 - min2), abs(max2 - min1))
And I wound up getting the following error:
$ elixir/ch-2.exs
Example 1:
Input: @arr1 = (4, 5, 7)
@arr2 = (9, 1, 3, 4)
** (FunctionClauseError) no function clause matching in Enum.max_sort_fun/1
The following arguments were given to Enum.max_sort_fun/1:
# 1
5
Attempted function clauses (showing 2 out of 2):
defp max_sort_fun(sorter) when is_function(sorter, 2)
defp max_sort_fun(module) when is_atom(module)
(elixir 1.18.3) lib/enum.ex:1919: Enum.max_sort_fun/1
(elixir 1.18.3) lib/enum.ex:1916: Enum.max/3
elixir/ch-2.exs:13: PWC.solution/2
elixir/ch-2.exs:18: (file)
So I immediately went to the Elixir REPL to figure out where I went wrong.
$ iex
Erlang/OTP 27 [erts-15.2.7] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [dtrace]
Interactive Elixir (1.18.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {arr1, arr2} = {[4, 5, 7], [9, 1, 3, 4]}
{[4, 5, 7], [9, 1, 3, 4]}
iex(2)> arr1
[4, 5, 7]
iex(3)> Enum.min(arr1)
4
iex(4)> Enum.max(arr1)
7
iex(5)> Enum.min(arr2)
1
iex(6)> Enum.max(arr2)
9
iex(7)> {min1, max1} = {Enum.min(arr1), Enum.max(arr1)}
{4, 7}
iex(8)> {min2, max2} = {Enum.min(arr2), Enum.max(arr2)}
{1, 9}
So it wasn’t the Enum.max/3
call on line 5 that was causing my problem.
iex(9)> Enum.max(abs(max1 - min2), abs(max2 - min1))
** (FunctionClauseError) no function clause matching in Enum.max_sort_fun/1
The following arguments were given to Enum.max_sort_fun/1:
# 1
5
Attempted function clauses (showing 2 out of 2):
defp max_sort_fun(sorter) when is_function(sorter, 2)
defp max_sort_fun(module) when is_atom(module)
(elixir 1.18.3) lib/enum.ex:1919: Enum.max_sort_fun/1
(elixir 1.18.3) lib/enum.ex:1916: Enum.max/3
iex:9: (file)
Ok, so it was line 7! Is the Kernel.abs/1
a problem?
iex(9)> abs(max1 - min2)
6
No, that’s not it. Wait…what’s the definition of Enum.max/3
again?
max(enumerable, sorter \\ &>=/2, empty_fallback \\ fn -> raise Enum.EmptyError end)
D’oh! Once again, I’m bitten by the perl-ish habit of just passing multiple values to a function and depending on the language to coerce those value into a list. Once I passed Enum.max/3
a list, everything worked:
iex(10)> Enum.max([abs(max1 - min2), abs(max2 - min1)])
6
iex(11)> ^C
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
(l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
def max_distance(arr1, arr2) do
{min1, max1} = {Enum.min(arr1), Enum.max(arr1)}
{min2, max2} = {Enum.min(arr2), Enum.max(arr2)}
Enum.max([abs(max1 - min2), abs(max2 - min1)])
end
View the entire Elixir script for this task on GitHub.
Here’s all my solutions in GItHub: https://github.com/packy/perlweeklychallenge-club/tree/master/challenge-338/packy-anderson