Perl Weekly Challenge: Week 255
Challenge 1:
Odd Character
You are given two strings,
$s
and$t
. The string$t
is generated using the shuffled characters of the string$s
with an additional character.Write a script to find the additional character in the string
$t
.
Example 1
Input: $s = "Perl" $t = "Preel"
Output: "e"
Example 2
Input: $s = "Weekly" $t = "Weeakly"
Output: "a"
Example 3
Input: $s = "Box" $t = "Boxy"
Output: "y"
Raku makes short work of this problem using its' extensive support for sets.
say q{"}, (@*ARGS[0].comb.Mix ∖ @*ARGS[1].comb.Mix).keys.join, q{"}
This one-liner accepts two command-line arguments. The first is the string $s
in the examples and the second is $c
. The first string is split into individual characters with .comb()
and cast to a Mix
. This Raku data type is equivalent to a C++ multiset
. i.e. it is a set that can hold more than one element with the same value. This is necessary because a letter might occur
multiple times in our input. The second string is treated in the same way. The ∖
operator returns the difference between the two
Mix
es as another Mix
whose .keys()
method provides the elements in it. (There should only be one.) The rest of the code is
to make the output look like that in the examples.
Perl doesn't have sets or set operations built in. I could have used a module or recycle some of the replacement code I've used in previous challenges but I chose a different approach.
As in Raku, $s
and $t
are picked up from the command-line arguments.
A hash is created to hold characters.
my %chars;
$t
is split()
into individual characters and they are added into the hash. The keyd are the character themselves
and the values are the number of times each character occurs.
for my $c (split //, $t) {
$chars{$c}++;
}
Now we split and iterate through $s
but this time every time a character occurs, one is subtracted from its value in the hash.
for my $c (split //, $s) {
$chars{$c}--;
}
By the end, most keys in the hash will have a value of 0; one will have a value of 1. This is the target of our search so
we find it with grep()
and print it out in a nice format.
say q{"}, (join q{}, grep { $chars{$_} > 0 } keys %chars), q{"};
Challenge 2:
Most Frequent Word
You are given a paragraph
$p
and a banned word$w
.Write a script to return the most frequent word that is not banned.
Example 1
Input: $p = "Joe hit a ball, the hit ball flew far after it was hit."
$w = "hit"
Output: "ball"
The banned word "hit" occurs 3 times.
The other word "ball" occurs 2 times.
Example 2
Input: $p = "Perl and Raku belong to the same family. Perl is the most popular language in the weekly challenge."
$w = "the"
Output: "Perl"
The banned word "the" occurs 3 times.
The other word "Perl" occurs 2 times.
$p
and $w
are taken from the command-line arguments.
A hash will hold how many times each word in the paragraph occurs.
my %count;
A word is defined as a sequence of characters separated by white-space, commas or periods. Words are extracted from $p
with
.split()
and a regular expression.
my @words = $p.split(/<[\s \, \.]>+/);
The words are added to the hash along with the number of times they occur.
for @words -> $word {
%count{$word}++;
}
The count for the "banned" word, $w
, is removed from the hash.
%count{$w}:delete;
The keys of the hash (i.e. the words) are sorted by frequency; most frequent to least. The first is printed out.
%count.keys.sort({ %count{$^b} <=> %count{$^a} }).first.say;
This is the Perl version which works the same way.
my %count;
my @words = split /[\s\,\.]+/, $p;
for my $word (@words) {
$count{$word}++;
}
delete %count{$w};
say [sort { $count{$b} <=> $count{$a} } keys %count]->[0];