Advent Calendar 2024
| Day 4 | Day 5 | Day 6 |
The gift is presented by Laurent Rosenfeld
. Today he is talking about his solution to The Weekly Challenge - 255. This is re-produced for Advent Calendar 2024
from the original post 1. and post 2.
Task 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.
Odd Character in Raku
This task is really simple in Raku
: we simply convert each input string into a Bag
of its letters, and then use the (-) infix
set difference operator to find the extra item in $t
. So we end up with a short one-line subroutine.
sub odd-char ($s, $t) {
return ~ ($t.comb.Bag (-) $s.comb.Bag);
}
for <Perl Preel>, <Weekly Weeakly>, <Box Boxy> -> @test {
printf "%-8s %-8s => ", @test;
say odd-char @test[0], @test[1];
}
This program displays the following output:
$ raku ./odd-characters.raku
Perl Preel => e
Weekly Weeakly => a
Box Boxy => y
Odd Character in Perl
The solution is slightly more complicated in Perl
, because Perl
doesn’t have Bags
and set
difference operators. We can easily replace bags with hashes (with values being the frequency of each letter). Then we have to find the extra hash item in %t
.
use strict; use warnings; use feature 'say';
sub odd_char {
my (%s, %t);
%s = map { $_ => ++$s{$_} } split //, $_[0];
%t = map { $_ => ++$t{$_} } split //, $_[1];
my @result = grep { (not defined $s{$_})
or $t{$_} - $s{$_} > 0 } keys %t;
}
for my $test ([<Perl Preel>], [<Weekly Weeakly>], [<Box Boxy>]) {
printf "%-8s %-8s => ", @$test;
say odd_char $test->[0], $test->[1];
}
This program displays the following output:
$ perl ./odd-characters.pl
Perl Preel => e
Weekly Weeakly => a
Box Boxy => y
Task 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.
Most Frequent Word in Raku
We first use the tr///
in-place transliteration operator to remove punctuation characters from the input paragraph, which makes it possible to use the words to split the paragraph into words. We then use grep
to remove the banned word from the word list and convert the resulting list into a Bag
, histo (for histogram). Finally, we return the item from the bag having the highest frequency.
sub most-frequent-word ($para is copy, $banned) {
$para ~~ tr/,.:;?!//;
my $histo = $para.words.grep({$_ ne $banned}).Bag;
return $histo.keys.max({$histo{$_}});
}
my $t = "Joe hit a ball, the hit ball flew far after it was hit.";
printf "%-30s... => ", substr $t, 0, 28;
say most-frequent-word $t, "hit";
$t = "Perl and Raku belong to the same family. Perl is the most popular language in the weekly challenge.";
printf "%-30s... => ", substr $t, 0, 28;
say most-frequent-word $t, "the";
This program displays the following output:
$ raku ./most-frequent-word.raku
Joe hit a ball, the hit ball ... => ball
Perl and Raku belong to the ... => Perl
Most Frequent Word in Perl
This is a port to Perl
of the Raku
program above, using a hash
instead of a Bag
and the split
function instead of words.
use strict;
use warnings;
use feature 'say';
sub most_frequent_word {
my ($para, $banned) = @_;
$para =~ tr/,.:;?!//;
my %histo;
%histo = map { $_ => ++$histo{$_} }
grep {$_ ne $banned} split /\W/, $para;
return (sort { $histo{$b} <=> $histo{$a} } keys %histo )[0];
}
my $t = "Joe hit a ball, the hit ball flew far after it was hit.";
printf "%-30s... => ", substr $t, 0, 28;
say most_frequent_word $t, "hit";
$t = "Perl and Raku belong to the same family. Perl is the most popular language in the weekly challenge.";
printf "%-30s... => ", substr $t, 0, 28;
say most_frequent_word $t, "the";
This program displays the following output:
$ perl ./most-frequent-word.pl
Joe hit a ball, the hit ball ... => ball
Perl and Raku belong to the ... => Perl
If you have any suggestion then please do share with us perlweeklychallenge@yahoo.com.