Perl Weekly Challenge 253.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 253.
Task 1: Split Strings
Submitted by: Mohammad S Anwar
You are given an array of strings and a character separator.
Write a script to return all words separated by the given character
excluding empty string.
Example 1
Input: @words = ("one.two.three","four.five","six")
$separator = "."
Output: "one","two","three","four","five","six"
Example 2
Input: @words = ("$perl$$", "$$raku$")
$separator = "$"
Output: "perl","raku"
Perl has a split
operator that fits nicely into this task. The
problem is that the separator may be interpreted as a special
character within a regular expression. Thus, I escape it with slashes
when constructing the argument of split. I further filter out empty
strings with grep
. The results fit a oneliner.
Example 1:
perl -E '
$s=shift; @x=@ARGV; push @r, grep {/./} split /[$s]/ for(@x); say "sep: $s, in: @x => @r"
' . one.two.three four.five six
Results:
sep: ., in: one.two.three four.five six => one two three four five six
Example 2:
perl -E '
$s=shift; @x=@ARGV; push @r, grep {/./} split /[$s]/ for(@x); say "sep: $s, in: @x => @r"
' '$' '$perl$$' '$$raku$'
Results:
sep: $, in: $perl$$ $$raku$ => perl raku
Full code:
1 # Perl weekly challenge 253
2 # Task 1: Split Strings
3 #
4 # See https://wlmb.github.io/2024/01/22/PWC253/#task-1-split-strings
5 use v5.36;
6 die <<~"FIN" unless @ARGV;
7 Usage: $0 S W1 [W2...]
8 to separate words W1 W2... at separator character S.
9 FIN
10 my $separator = shift;
11 die "Only single characterr allowed as separator: $separator" unless $separator=~/^.$/;
12 my @results;
13 push @results, grep {/./} split /[$separator]/ for (@ARGV);
14 say "Separator: $separator, input: @ARGV => output: @results";
Examples:
./ch-1.pl . one.two.three four.five six
./ch-1.pl '$' '$perl$$' '$$raku$'
Results:
Separator: ., input: one.two.three four.five six => output: one two three four five six
Separator: $, input: $perl$$ $$raku$ => output: perl raku
Task 2: Weakest Row
Submitted by: Mohammad S Anwar
You are given an m x n binary matrix i.e. only 0 and 1 where 1 always appear before 0.
A row i is weaker than a row j if one of the following is true:
a. The number of 1s in row i is less than the number of 1s in row j.
b. Both rows have the same number of 1 and i < j.
Write a script to return the order of rows from weakest to strongest.
Example 1
Input: $matrix = [
[1, 1, 0, 0, 0],
[1, 1, 1, 1, 0],
[1, 0, 0, 0, 0],
[1, 1, 0, 0, 0],
[1, 1, 1, 1, 1]
]
Output: (2, 0, 3, 1, 4)
The number of 1s in each row is:
- Row 0: 2
- Row 1: 4
- Row 2: 1
- Row 3: 2
- Row 4: 5
Example 2
Input: $matrix = [
[1, 0, 0, 0],
[1, 1, 1, 1],
[1, 0, 0, 0],
[1, 0, 0, 0]
]
Output: (0, 2, 3, 1)
The number of 1s in each row is:
- Row 0: 1
- Row 1: 4
- Row 2: 1
- Row 3: 1
I can input each row as a binary string, split
into and array and
sort
its row indices by the sum of its members and by the indices
themselves. The result fits a two-liner.
Example 1:
perl -MList::Util=sum0 -E '
push @x, [split ""] for(@ARGV); say p(@x), "\n-> ", join " ", sort{f($a)<=>f($b)||$a<=>$b}
0..@x-1; sub p(@m){return "[\n", (map {" [ @$_ ]\n"} @m), "]"} sub f($i){sum0 $x[$i]->@*}
' 11000 11110 10000 11000 11111
Results:
[
[ 1 1 0 0 0 ]
[ 1 1 1 1 0 ]
[ 1 0 0 0 0 ]
[ 1 1 0 0 0 ]
[ 1 1 1 1 1 ]
]
-> 2 0 3 1 4
Example 2:
perl -MList::Util=sum0 -E '
push @x, [split ""] for(@ARGV); say p(@x), "\n-> ", join " ", sort{f($a)<=>f($b)||$a<=>$b}
0..@x-1; sub p(@m){return "[\n", (map {" [ @$_ ]\n"} @m), "]"} sub f($i){sum0 $x[$i]->@*}
' 1000 1111 1000 1000
Results:
[
[ 1 0 0 0 ]
[ 1 1 1 1 ]
[ 1 0 0 0 ]
[ 1 0 0 0 ]
]
-> 0 2 3 1
The full code adds a few checks and uses a Schwartzian transform to avoid recomputing sums (and get fancy):
1 # Perl weekly challenge 253
2 # Task 2: Weakest Row
3 #
4 # See https://wlmb.github.io/2024/01/22/PWC253/#task-2-weakest-row
5 use v5.36;
6 use List::Util qw(all sum0);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 R0 [R1...]
9 to order the indices of the rows R_i of a binary matrix
10 from weakest to strongest, where R_i is represented as
11 a binary string.
12 FIN
13 die "Only binary strings allowed" unless all {m/^[01]+$/} @ARGV;
14 my @matrix;
15 push @matrix, [split ""] for(@ARGV);
16 say format_matrix(@matrix), "\n-> ",
17 join " ",
18 map {$_->[0]}
19 sort {$a->[1] <=> $b->[1] || $a->[0] <=> $b->[0]}
20 map {[$_, sum0 $matrix[$_]->@*]}
21 0..@matrix-1;
22 sub format_matrix(@m){
23 return "[\n", (map {" [ @$_ ]\n"} @m), "]"
24 }
Examples:
./ch-2.pl 11000 11110 10000 11000 11111
./ch-2.pl 1000 1111 1000 1000
Results:
[
[ 1 1 0 0 0 ]
[ 1 1 1 1 0 ]
[ 1 0 0 0 0 ]
[ 1 1 0 0 0 ]
[ 1 1 1 1 1 ]
]
-> 2 0 3 1 4
[
[ 1 0 0 0 ]
[ 1 1 1 1 ]
[ 1 0 0 0 ]
[ 1 0 0 0 ]
]
-> 0 2 3 1
/;