This is my response to The Weekly Challenge #255.
$s
and $t
. The string $t
is generated using the shuffled characters of the string $s
with an additional character.
$t
.
Input: $s = "Perl" $t = "Preel"
Output: "e"
Example 2:
Input: $s = "Box" $t = "Boxy"
Output: "y"
#! /usr/bin/env raku
unit sub MAIN ($s where $s.chars > 0, # [1]
$t where $t.chars == $s.chars + 1, # [1a]
:v(:$verbose));
my $t-bag = $t.comb.Bag; # [2]
my $s-bag = $s.comb.Bag; # [2a]
my $add = $t-bag (^) $s-bag; # [3]
if $verbose
{
say ":s: { $s-bag.raku }";
say ":t: { $t-bag.raku }";
say ":addition: { $add.raku }";
}
die "Not one additional letter, but { $add.elems } ({ $add.keys.join(",") })"
unless $add.elems == 1; # [4]
say $add.keys.first; # [5]
[1] The first string must have at least one character, and the second string must have one character more than the first one.
[2] Turn the strings into Bag
s of individual characters.
(The keys will be the original characters (without duplicates), and the
values are the frequency.)
See docs.raku.org/routine/Bag for more information about Bag
.
[3] Apply the symmetric set difference operator (^)
to get the difference between the two Bags, i.e. the added letter(s).
See
docs.raku.org/language/setbagmix#Set_operators_that_return_a_QuantHash and scroll
down to the symmetric set difference operator (^)
.
[4] Protest if the difference has more than one character.
[5] We have Bag with one element. Using keys
will
return a list of one key, and first
will give that one. This is
the added character, and we print it
See docs.raku.org/routine/first for more information about first
.
Running it:
$ ./odd-character Perl Preel
e
$ ./odd-character Box Boxy
y
Looking good.
With verbose mode:
$ ./odd-character -v "Perl" "Preel"
:s: ("P"=>1,"e"=>1,"r"=>1,"l"=>1).Bag
:t: ("e"=>2,"r"=>1,"l"=>1,"P"=>1).Bag
:addition: ("e"=>1).Bag
e
$ ./odd-character -v Box Boxy
:s: ("o"=>1,"x"=>1,"B"=>1).Bag
:t: ("y"=>1,"o"=>1,"B"=>1,"x"=>1).Bag
:addition: ("y"=>1).Bag
y
$p
and a banned word $w
.
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
#! /usr/bin/env raku
unit sub MAIN ($p where $p.chars > 1, # [1]
$w where $w ~~ /^\w+$/, # [2]
:v(:$verbose));
my $p2 = $p.trans({ '.' => ' ', ',' => ' ' }); # [3]
my $words = $p2.words.Bag; # [4]
my $count = $words{$w}; # [5]
my $without = $words (-) $w xx $count; # [6]
my @sorted = $without.sort({ $^b.value <=> $^a.value }); # [7]
if $verbose
{
say ":p: '$p'";
say ":p: '$p2' (modified)";
say ":word '$w' found $count times";
say ":Words: { $words.raku }";
say ":Without: { $without.raku }";
say ":Sorted: { @sorted.raku }";
}
say @sorted.first.key; # [8]
[1] Ensure that the paragraph has at least one character.
[2] Ensure that the banned word contains word characters
only (the \w+
regex), one or more of them.
[3] Use trans
to translate commas and periods
(as two pairs) to spaces, as the words
method (see [4]) does
not consider those characters as word separators.
See docs.raku.org/routine/trans for more information about trans
.
[4] Use words
to split the sentence into separate
words. Then apply Bag
to turn that list of words into a Bag
,
thus counting the words for us.
See docs.raku.org/routine/words for more information about words
.
[5] Get the number of times the word occurs in the sentence (by looking it up in the Bag).
[6]
Remove the banned word, exactly as many times as it occurs
in the sentence, using the list repetition operator xx
and the
set difference operator (-)
.
See docs.raku.org/routine/xx for more information about xx
.
See
docs.raku.org/language/setbagmix#Set_operators_that_return_a_QuantHash and scroll
down to the set difference operator (-)
.
[7] Sort the Bag of non-banned words on the frequency
(the value
part of the Pairs), with the largest first. The result
is a list of Pair objects.
See docs.raku.org/routine/value for more information about value
.
[8] Take the first Pair object (with first
, and print the
value (i.e. the word), with value
).
Running it:
$ ./most-frequent-word "Joe hit a ball, the hit ball flew far after it was \
hit." hit
ball
$ ./most-frequent-word "Perl and Raku belong to the same family. Perl is \
the most popular language in the weekly challenge." the
Perl
Looking good.
With verbose mode:
$ ./most-frequent-word -v "Joe hit a ball, the hit ball flew far after it \
was hit." hit
:p: 'Joe hit a ball, the hit ball flew far after it was hit.'
:p: 'Joe hit a ball the hit ball flew far after it was hit ' (modified)
:word 'hit' found 3 times
:Words: ("the"=>1,"after"=>1,"was"=>1,"it"=>1,"far"=>1,"hit"=>3,"Joe"=>1,
"flew"=>1,"ball"=>2,"a"=>1).Bag
:Without: ("flew"=>1,"ball"=>2,"Joe"=>1,"the"=>1,"was"=>1,"a"=>1,"far"=>1,
"it"=>1,"after"=>1).Bag
:Sorted: [:ball(2), :flew(1), :Joe(1), :the(1), :was(1), :a(1), :far(1),
:it(1), :after(1)]
ball
$ ./most-frequent-word -v "Perl and Raku belong to the same family. Perl \
is the most popular language in the weekly challenge." the
:p: 'Perl and Raku belong to the same family. Perl is the most popular \
language in the weekly challenge.'
:p: 'Perl and Raku belong to the same family Perl is the most popular \
language in the weekly challenge ' (modified)
:word 'the' found 3 times
:Words: ("family"=>1,"to"=>1,"popular"=>1,"language"=>1,"Perl"=>2,
"belong"=>1,"most"=>1,"the"=>3,"and"=>1,"in"=>1,"is"=>1,
"Raku"=>1,"same"=>1,"weekly"=>1,"challenge"=>1).Bag
:Without: ("popular"=>1,"same"=>1,"is"=>1,"Perl"=>2,"challenge"=>1,
"family"=>1,"most"=>1,"to"=>1,"belong"=>1,"and"=>1,"in"=>1,
"weekly"=>1,"Raku"=>1,"language"=>1).Bag
:Sorted: [:Perl(2), :popular(1), :same(1), :is(1), :challenge(1),
:family(1), :most(1), :to(1), :belong(1), :and(1), :in(1),
:weekly(1), :Raku(1), :language(1)]
Perl
And that's it.