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