Perl Weekly Challenge 333.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 333.
Task 1: Straight Line
Submitted by: Mohammad Sajid Anwar
You are given a list of co-ordinates.
Write a script to find out if the given points make a straight line.
Example 1
Input: @list = ([2, 1], [2, 3], [2, 5])
Output: true
Example 2
Input: @list = ([1, 4], [3, 4], [10, 4])
Output: true
Example 3
Input: @list = ([0, 0], [1, 1], [2, 3])
Output: false
Example 4
Input: @list = ([1, 1], [1, 1], [1, 1])
Output: true
Example 5
Input: @list = ([1000000, 1000000], [2000000, 2000000], [3000000, 3000000])
Output: true
Two vectors V1 and V2 are on the same straight line through the origin if they are linearly dependent, i.e., the determinant |Vij| of their coefficients Vij is zero. Three points P0, P1 and P2 are on the same straight line if P1-P0 and P2-P0 are on the same straight line through the origin. I can use this criteria to check that several points P2, P3…Pn are on the same line as P0 and P1. Nevertheless, I have to make sure that P0 and P1 are different, to make sure they define a single line. Using the Perl Data Language this yields a two liner.
Examples:
perl -MPDL -MPDL::NiceSlice -E '
for(@ARGV){$p=pdl($_);$q=$p(:,1:-1)-$p(:,0);$v=$q->mv(1,0)->whereND($q->magnover!=0)->mv(0,1);
say "$_ -> ", $v->dim(1)==0||(pdl($v(:,0),$v(:,1:-1))->mv(-1,1)->det==0)->all?"T":"F";
}
' "[[2 1][2 3][2 5]]" "[[1 4][3 4][10 4]]" "[[0 0][1 1][2 3]]" "[[1 1][1 1][1 1]]" \
"[[1000000 1000000][2000000 2000000][3000000 3000000]]"
Results:
[[2 1][2 3][2 5]] -> T
[[1 4][3 4][10 4]] -> T
[[0 0][1 1][2 3]] -> F
[[1 1][1 1][1 1]] -> T
[[1000000 1000000][2000000 2000000][3000000 3000000]] -> T
The explanation is given in the full code below:
1 # Perl weekly challenge 333
2 # Task 1: Straight Line
3 #
4 # See https://wlmb.github.io/2025/08/04/PWC333/#task-1-straight-line
5 use v5.36;
6 use experimental qw(try);
7 use PDL;
8 use PDL::NiceSlice;
9
10 die <<~"FIN" unless @ARGV;
11 Usage: $0 A1 A2...
12 to test if the arrays An of 2D points lie on a straight line.
13 An are strings of the form "[[x1 y1][x2 y2]...[xn yn]]"
14 FIN
15 my $result;
16 for(@ARGV){
17 try {
18 my $points = pdl($_);
19 die "Expected an array of 2D vectors: $_"
20 unless $points->ndims==2 and $points->dim(0)==2;
21 $result=1, next if $points->dim(1)<=2; # two or less points lie on a straight line
22 my $differences= ($points(:,1:-1)-$points(:,0)); # subtract first point from all others
23 # Throw away points that duplicate the first
24 my $vectors = $differences->mv(1,0)->whereND($differences->magnover!=0)->mv(0,1);
25 $result=1, next if $vectors->dim(1)==0; # one vector is in a straight line
26 # make matrices with the first vector and each of the others.
27 # The indices are the cartesian index, the row index and the number of matrix
28 my $matrices=pdl($vectors(:,0), $vectors(:,1:-1))->mv(-1,1);
29 my $dets = $matrices->det; # array of determinants
30 $result=($dets==0)->all, next;
31 }
32 catch($e){
33 say $e;
34 }
35 }
36 continue {
37 say "$_ -> ", $result?"True":"False";
38 }
Examples:
./ch-1.pl "[[2 1][2 3][2 5]]" "[[1 4][3 4][10 4]]" "[[0 0][1 1][2 3]]" "[[1 1][1 1][1 1]]" \
"[[1000000 1000000][2000000 2000000][3000000 3000000]]"
Results:
[[2 1][2 3][2 5]] -> True
[[1 4][3 4][10 4]] -> True
[[0 0][1 1][2 3]] -> False
[[1 1][1 1][1 1]] -> True
[[1000000 1000000][2000000 2000000][3000000 3000000]] -> True
Task 2: Duplicate Zeros
Submitted by: Mohammad Sajid Anwar
You are given an array of integers.
Write a script to duplicate each occurrence of zero, shifting the remaining elements
to the right. The elements beyond the length of the original array are not written.
Example 1
Input: @ints = (1, 0, 2, 3, 0, 4, 5, 0)
Output: (1, 0, 0, 2, 3, 0, 0, 4)
Each zero is duplicated.
Elements beyond the original length (like 5 and last 0) are discarded.
Example 2
Input: @ints = (1, 2, 3)
Output: (1, 2, 3)
No zeros exist, so the array remains unchanged.
Example 3
Input: @ints = (1, 2, 3, 0)
Output: (1, 2, 3, 0)
Example 4
Input: @ints = (0, 0, 1, 2)
Output: (0, 0, 0, 0)
Example 5
Input: @ints = (1, 2, 0, 3, 4)
Output: (1, 2, 0, 0, 3)
I use map
and the short-cut disjunction ||
to duplicate zeroes
and then I keep as many numbers as the cardinality of the input, taken
from @ARGV
. This yields a half-liner.
Examples:
perl -E '
say "@ARGV -> ", join " ", (map{$_||(0,0)}@ARGV)[0..@ARGV-1];
' 1 0 2 3 0 4 5 0
Results:
1 0 2 3 0 4 5 0 -> 1 0 0 2 3 0 0 4
perl -E '
say "@ARGV -> ", join " ", (map{$_||(0,0)}@ARGV)[0..@ARGV-1];
' 1 2 3
Results:
1 2 3 -> 1 2 3
perl -E '
say "@ARGV -> ", join " ", (map{$_||(0,0)}@ARGV)[0..@ARGV-1];
' 1 2 3 0
Results:
1 2 3 0 -> 1 2 3 0
perl -E '
say "@ARGV -> ", join " ", (map{$_||(0,0)}@ARGV)[0..@ARGV-1];
' 0 0 1 2
Results:
0 0 1 2 -> 0 0 0 0
perl -E '
say "@ARGV -> ", join " ", (map{$_||(0,0)}@ARGV)[0..@ARGV-1];
' 1 2 0 3 4
Results:
1 2 0 3 4 -> 1 2 0 0 3
1 # Perl weekly challenge 333
2 # Task 2: Duplicate Zeros
3 #
4 # See https://wlmb.github.io/2025/08/04/PWC333/#task-2-duplicate-zeros
5 use v5.36;
6 die <<~"FIN" unless @ARGV;
7 Usage: $0 N1 N2...
8 to duplicate zeroes in the list N1 N2..., keeping the length.
9 FIN
10 say "@ARGV -> ", join " ", (
11 map{$_||(0,0)} @ARGV) # duplicate zeros
12 [0..@ARGV-1]; # keep size of input
Example:
./ch-2.pl 1 0 2 3 0 4 5 0
./ch-2.pl 1 2 3
./ch-2.pl 1 2 3 0
./ch-2.pl 0 0 1 2
./ch-2.pl 1 2 0 3 4
Results:
1 0 2 3 0 4 5 0 -> 1 0 0 2 3 0 0 4
1 2 3 -> 1 2 3
1 2 3 0 -> 1 2 3 0
0 0 1 2 -> 0 0 0 0
1 2 0 3 4 -> 1 2 0 0 3
/;