I don’t know, this week there’s no lyrics that the problems are inspiring. The closest I can get is Shout by The Isley Brothers, so let’s go with that…
Let’s dive into Perl Weekly Challenge 253!
Task 1: Split Strings
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"
Approach
This is fairly straightforward: split strings on the separator, filter out empty strings.
Raku
The :skip-empty
named parameter handles filtering out the empty strings.
sub splitOnSeparator(@words, $separator) {
my @output;
for @words -> $str {
@output.append( $str.split($separator, :skip-empty) );
}
return @output;
}
View the entire Raku script for this task on GitHub.
Perl
In Perl, we need to use the quotemeta
function (or \Q
within the regular expression, like I did) to escape any metacharacters in the separator (which both .
and $
are). And because the split doesn’t have a parameter to skip empty results, we have to filter them out by grepping out strings that have match a regular expression anchored at the beginning and end with no characters in-between.
sub splitOnSeparator($separator, @words) {
my @output;
foreach my $str ( @words ) {
push @output, grep { !/^$/ } split(/\Q$separator/, $str);
}
return @output;
}
View the entire Perl script for this task on GitHub.
Python
I keep forgetting about Python’s extend
method on lists.
def splitOnSeparator(words, separator):
output = []
for str in words:
output.extend(
list(filter(lambda w: w>"", str.split(separator)))
)
return output
View the entire Python script for this task on GitHub.
Task 2: Weakest Row
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
Approach
This feels like a map then sort: loop over the matrix, counting the 1
s in each row (though, because it’s defined to be just 1
s and 0
s, we can just sum
the row). Then do a sort of the indices based on that count. In fact, we’ve done a sort like this before, in the Most Frequent Letter Pair task for PWC 247.
Raku
I’m borrowing my matrix printing code from PWC 248. Once again, I have to shout out to the Raku List method .end
.
sub weakestRows(@matrix) {
my @oneCount = @matrix.map({ $_.sum });
my @weakest = (0 .. @oneCount.end).sort: {
# sort by count first
@oneCount[$^a] <=> @oneCount[$^b]
||
# then by index order
$^a <=> $^b
};
return @weakest;
}
View the entire Raku script for this task on GitHub.
Perl
Just the usual Raku-to-Perl changes.
use List::Util qw( sum );
sub weakestRows(@matrix) {
my @oneCount = map { sum(@$_) } @matrix;
my @weakest = sort {
# sort by count first
$oneCount[$a] <=> $oneCount[$b]
||
# then by index order
$a cmp $b
} (0 .. $#oneCount);
return @weakest;
}
View the entire Perl script for this task on GitHub.
Python
And, just like I did back in PWC 247, I’d like to point out that Python’s Decorate-Sort-Undecorate idiom is really just a Schwartzian Transformation.
def weakestRows(matrix):
oneCount = [ sum(row) for row in matrix ]
# sort the rows by their oneCount values
# use the Decorate-Sort-Undecorate idiom
# to convert the dict into a list
# https://docs.python.org/3/howto/sorting.html#decorate-sort-undecorate
decorated = [
(oneCount[i], i) for i in range(len(oneCount))
]
sorted_tuples = sorted(
decorated,
# the - before the first element sorts descending
key=lambda k: (k[0], k[1])
)
weakest = [ t[1] for t in sorted_tuples ]
return weakest
View the entire Python script for this task on GitHub.
Here’s all my solutions in GItHub: https://github.com/packy/perlweeklychallenge-club/tree/master/challenge-253/packy-anderson
Pingback: Perl Weekly Challenge: Odd Char Seems to be the Most Frequent Word | Packy’s Place