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

/;

Written on August 4, 2025