Perl Weekly Challenge: Week 343
In other news, I got my Hacktoberfest 2025 t-shirt by contributing solutions to the Weekly Challenge.
Challenge 1:
Zero Friend
You are given a list of numbers.
Find the number that is closest to zero and return its distance to zero.
Example 1
Input: @nums = (4, 2, -1, 3, -2)
Output: 1
Values closest to 0: -1 and 2 (distance = 1 and 2)
Example 2
Input: @nums = (-5, 5, -3, 3, -1, 1)
Output: 1
Values closest to 0: -1 and 1 (distance = 1)
Example 3
Input: @ums = (7, -3, 0, 2, -8)
Output: 0
Values closest to 0: 0 (distance = 0)
Exact zero wins regardless of other close values.
Example 4
Input: @nums = (-2, -5, -1, -8)
Output: 1
Values closest to 0: -1 and -2 (distance = 1 and 2)
Example 5
Input: @nums = (-2, 2, -4, 4, -1, 1)
Output: 1
Values closest to 0: -1 and 1 (distance = 1)
We can solve this in Raku as a one-liner.
@*ARGS.map({ (0 - $_).abs }).sort({ $^a <=> $^b })[0].say
Using the command-line arguments as input, we first use .map() to find the distance of each element to 0 by subtracting the value of the element from 0 and taking the absolute value of the result with .abs(). We then
.sort() all these absolute values in ascending numeric order. The first value (index 0) will be the closest distance to 0; we print it out with .say().
We can be just as concise in Perl though the syntax is a little different. The main difference to note is that
we have to add 0 + before the calculation to force array context.
say 0 + (sort { $a <=> $b} map { abs(0 - $_) } @ARGV)[0]
Challenge 2:
Champion Team
You have n teams in a tournament. A matrix grid tells you which team is stronger between any two teams:
If grid[i][j] == 1, then team i is stronger than team j
If grid[i][j] == 0, then team j is stronger than team i
Find the champion team - the one with most wins, or if there is no single such team, the strongest of the teams with most wins. (You may assume that there is a definite answer.)
Example 1
Input: @grid = (
[0, 1, 1],
[0, 0, 1],
[0, 0, 0],
)
Output: Team 0
[0, 1, 1] => Team 0 beats Team 1 and Team 2
[0, 0, 1] => Team 1 beats Team 2
[0, 0, 0] => Team 2 loses to all
Example 2
Input: @grid = (
[0, 1, 0, 0],
[0, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
)
Output: Team 3
[0, 1, 0, 0] => Team 0 beats only Team 1
[0, 0, 0, 0] => Team 1 loses to all
[1, 1, 0, 0] => Team 2 beats Team 0 and Team 1
[1, 1, 1, 0] => Team 3 beats everyone
Example 3
Input: @grid = (
[0, 1, 0, 1],
[0, 0, 1, 1],
[1, 0, 0, 0],
[0, 0, 1, 0],
)
Output: Team 0
[0, 1, 0, 1] => Team 0 beats teams 1 and 3
[0, 0, 1, 1] => Team 1 beats teams 2 and 3
[1, 0, 0, 0] => Team 2 beats team 0
[0, 0, 1, 0] => Team 3 beats team 2
Of the teams with 2 wins, Team 0 beats team 1.
Example 4
Input: @grid = (
[0, 1, 1],
[0, 0, 0],
[0, 1, 0],
)
Output: Team 0
[0, 1, 1] => Team 0 beats Team 1 and Team 2
[0, 0, 0] => Team 1 loses to Team 2
[0, 1, 0] => Team 2 beats Team 1 but loses to Team 0
Example 5
Input: @grid = (
[0, 0, 0, 0, 0],
[1, 0, 0, 0, 0],
[1, 1, 0, 1, 1],
[1, 1, 0, 0, 0],
[1, 1, 0, 1, 0],
)
Output: Team 2
[0, 0, 0, 0, 0] => Team 0 loses to all
[1, 0, 0, 0, 0] => Team 1 beats only Team 0
[1, 1, 0, 1, 1] => Team 2 beats everyone except self
[1, 1, 0, 0, 0] => Team 3 loses to Team 2
[1, 1, 0, 1, 0] => Team 4 loses to Team 2
The input enters the script in command-line arguments. Each argument represents
a row of the grid where the columns are separated by whitespace. So the input
for example 1 would look like: "0 1 1" "0 0 1" "0 0 0" for instance.
The line below creates an array @grid based on this input using .map() and .words().
The elements, which are strings at this point, are converted back to numbers
using the hyper-operator. ».Int.
my @grid = @args.map({ $_.words».Int });
We store every teams' total wins in @wins which is created by summing each row
in @grid using the reduction operator [+] and .map().
my @wins = @grid.map({ [+] $_ });
The highest score found in @wins is stored in $max using the .max() method.
my $max = @wins.max;
@candidates uses .keys() and .grep() on @wins to collect the indices (team
numbers) of all teams who achieved the maximum score.
my @candidates = @wins.keys.grep({ @wins[$_] == $max });
One last issue must be dealt with. If more than one team shares the highest number of wins, we must break this tie to determine the champion.
We initially set $champion to the first candidate...
my $champion = @candidates[0];
...and then loop through the remaining candidates (using [1 .. *] to slice from index 1 onwards)
and check if the current champion lost to any other candidate (indicated by a 0 in the grid at @grid[$champion][$candidate]). If so, we make that candidate $champion instead.
for @candidates[1..*] -> $candidate {
if @grid[$champion][$candidate] == 0 {
$champion = $candidate;
}
}
Finally, we print out the $champion.
say $champion;
This is the Perl version. The way 2d arrays are implemented makes the code a little more ungainly but not that much longer.
my @grid;
my @wins;
We can populate @grid and @wins in the same loop.
for my $arg (@ARGV) {
my @row = split /\s+/, $arg;
push @grid, \@row;
push @wins, scalar grep { $_ } @row;
}
As we don't have a max() function, we sort @wins in ascending numeric order and take
the last element to be $max.
my $max = (sort {$a <=> $b} @wins)[-1];
my @candidates = grep { $wins[$_] == $max } keys @wins;
my $champion = $candidates[0];
for my $candidate (@candidates[1 .. $#candidates]) {
if ($grid[$champion]->[$candidate] == 0) {
$champion = $candidate;
}
}
say $champion;