Perl Weekly Challenge 314.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 314.
Task 1: Equal Strings
Submitted by: Mohammad Sajid Anwar
You are given three strings.
You are allowed to remove the rightmost character of a string to make all equals.
Write a script to return the number of operations to make it equal otherwise -1.
Example 1
Input: $s1 = "abc", $s2 = "abb", $s3 = "ab"
Output: 2
Operation 1: Delete "c" from the string "abc"
Operation 2: Delete "b" from the string "abb"
Example 2
Input: $s1 = "ayz", $s2 = "cyz", $s3 = "xyz"
Output: -1
Example 3
Input: $s1 = "yza", $s2 = "yzb", $s3 = "yzc"
Output: 3
A simple solution consists in first making all strings the same length.
- If all strings are equal, end.
- Cut the last letter of each
- Repeat.
If the resulting strings have zero length, there is a failure so print -1. Otherwise, print the number of characters removed. The result fits a two-liner.
Example 1:
perl -MList::Util=min,uniq -E '
$m=min map {length}@x=@ARGV;s/^(.{,$m})(.*)$/$1/, $r+=length $2 for @x;
while(uniq(@x)>1){s/^(.*).$/$1/ for(@x);$r+=@x}say "@ARGV -> ", length $x[0]?$r:-1;
' abc abb ab
Results:
abc abb ab -> 2
Example 2:
perl -MList::Util=min,uniq -E '
$m=min map {length}@x=@ARGV;s/^(.{,$m})(.*)$/$1/, $r+=length $2 for @x;
while(uniq(@x)>1){s/^(.*).$/$1/ for(@x);$r+=@x}say "@ARGV -> ", length $x[0]?$r:-1;
' ayz cyz xyz
Results:
ayz cyz xyz -> -1
Example 3:
perl -MList::Util=min,uniq -E '
$m=min map {length}@x=@ARGV;s/^(.{,$m})(.*)$/$1/, $r+=length $2 for @x;
while(uniq(@x)>1){s/^(.*).$/$1/ for(@x);$r+=@x}say "@ARGV -> ", length $x[0]?$r:-1;
' yza yzb yzc
Results:
yza yzb yzc -> 3
An alternative would be to analyze the strings from the start. Remove the first character of each string if all are equal and iterate until at least one is different. The result is then the number of remaining characters. This solution is slightly shorter and fits a longish one-liner.
Example 1:
perl -MList::Util=all -E '
@x=@ARGV;while(all {$p=substr $x[0],0,1; /^$p/}@x){++$l;s/.(.*)/$1/ for @x}say $l?length join "",@x:-1;
' abc abb ab
Results:
2
Example 2:
perl -MList::Util=all -E '
@x=@ARGV;while(all {$p=substr $x[0],0,1; /^$p/}@x){++$l;s/.(.*)/$1/ for @x}say $l?length join "",@x:-1;
' ayz cyz xyz
Results:
-1
Example 3:
#+begin_src bash :results output
perl -MList::Util=all -E '
@x=@ARGV;while(all {$p=substr $x[0],0,1; /^$p/}@x){++$l;s/.(.*)/$1/ for @x}say $l?length join "",@x:-1;
' yza yzb yzc
Results:
3
The corresponding full code is:
1 # Perl weekly challenge 314
2 # Task 1: Equal Strings
3 #
4 # See https://wlmb.github.io/2025/03/24/PWC314/#task-1-equal-strings
5 use v5.36;
6 use List::Util qw(all sum0);
7 die <<~"FIN" unless @ARGV and @ARGV%3==0;
8 Usage: $0 S11 S12 S13 S21 S22 S23...
9 to find how many times the strings Sn1 Sn2 Sn3 have to be cut
10 from their end so they become equal.
11 FIN
12 for my ($x, $y, $z)(@ARGV){
13 my @orig = my @strings = ($x, $y, $z);
14 my $iterations = 0;
15 while(all {my $p=substr $strings[0],0,1; /^$p/} @strings){ # if first characters coincide
16 ++$iterations;
17 s/^.(.*)/$1/ for @strings; # remove them
18 }
19 say "@orig -> ", $iterations ? sum0 map {length} @strings : -1;
20 }
21
Examples:
./ch-1.pl abc abb ab ayz cyz xyz yza yzb yzc
Results:
abc abb ab -> 2
ayz cyz xyz -> -1
yza yzb yzc -> 3
Task 2: Sort Column
Submitted by: Mohammad Sajid Anwar
You are given a list of strings of same length.
Write a script to make each column sorted lexicographically by deleting any non sorted columns.
Return the total columns deleted.
Example 1
Input: @list = ("swpc", "tyad", "azbe")
Output: 2
swpc
tyad
azbe
Column 1: "s", "t", "a" => non sorted
Column 2: "w", "y", "z" => sorted
Column 3: "p", "a", "b" => non sorted
Column 4: "c", "d", "e" => sorted
Total columns to delete to make it sorted lexicographically.
Example 2
Input: @list = ("cba", "daf", "ghi")
Output: 1
Example 3
Input: @list = ("a", "b", "c")
Output: 0
I map the strings to a 2D array of ordinal numbers using ord
and
store them in a ndarray using the Perl Data language PDL
. I
transpose the array so that each letter position corresponds to a row,
I sort the rows and compare them to the unsorted array. I have to
delete a row if any of its elements differ from the corresponding
element of the sorted array. I sum how many rows are to be deleted and
report the result. The code fits a one-liner.
Example 1:
perl -MPDL -E '
$s=($p=pdl(map{[map{ord}split ""]}@ARGV)->mv(1,0))->qsort;say "@ARGV -> ",($p!=$s)->orover->sum;
' swpc tyad azbe
Results:
swpc tyad azbe -> 2
Example 2:
perl -MPDL -E '
$s=($p=pdl(map{[map{ord}split ""]}@ARGV)->mv(1,0))->qsort;say "@ARGV -> ",($p!=$s)->orover->sum;
' cba daf ghi
Results:
cba daf ghi -> 1
Example 3:
perl -MPDL -E '
$s=($p=pdl(map{[map{ord}split ""]}@ARGV)->mv(1,0))->qsort;say "@ARGV -> ",($p!=$s)->orover->sum;
' a b c
Results:
a b c -> 0
The full code adds a few tests and converts to lower case on input.
1 # Perl weekly challenge 314
2 # Task 2: Sort Column
3 #
4 # See https://wlmb.github.io/2025/03/24/PWC314/#task-2-sort-column
5 use v5.36;
6 use PDL;
7 die <<~"FIN" unless @ARGV;
8 $0 S1 S2...
9 to count how many columns of a matrix formed by the n-th character
10 Cnm of the m-th string Sm has to be deleted so that the remaining columns
11 are sorted.
12 FIN
13 die "All strings have to be of the same length" unless pdl(map {length} @ARGV)->uniq->nelem==1;
14 my $matrix = pdl(map {[map {ord lc} split ""]} @ARGV)->mv(1,0);
15 my $sorted = $matrix->qsort;
16 say "@ARGV -> ",($matrix != $sorted)->orover->sum;
Example:
./ch-2.pl swpc tyad azbe
./ch-2.pl cba daf ghi
./ch-2.pl a b c
Results:
swpc tyad azbe -> 2
cba daf ghi -> 1
a b c -> 0