This is my response to The Weekly Challenge #331.
Input: $str = "The Weekly Challenge"
Output: 9
Example 2:
Input: $str = " Hello World "
Output: 5
Example 3:
Input: $str = "Let's begin the fun"
Output: 3
#! /usr/bin/env raku
unit sub MAIN ($str where $str.chars > 0, # [1]
:v(:$verbose));
say ": Last word: '{ $str.words.tail }'" if $verbose;
say $str.words.tail.chars; # [2]
[1] A string with at least one character. A short word, but I is a word. Grammatical pun intended.
[2]
Split the string into a list of words (with words
), pick
the very last one (with tail
), and print the length.
See docs.raku.org/routine/words for more information about words
.
See docs.raku.org/routine/tail for more information about tail
.
Running it:
$ ./last-word "The Weekly Challenge"
9
$ ./last-word " Hello World "
5
$ ./last-word "Let's begin the fun"
3
Looking good.
With verbose mode:
$ ./last-word -v "The Weekly Challenge"
: Last word: 'Challenge'
9
$ ./last-word -v " Hello World "
: Last word: 'World'
5
$ ./last-word -v "Let's begin the fun"
: Last word: 'fun'
3
source
and target
.
Buddy Strings
.
Input: $source = "fuck"
$target = "fcuk"
Output: true
The swapping of 'u' with 'c' makes it buddy strings.
Example 2:
Input: $source = "love"
$target = "love"
Output: false
Example 3:
Input: $source = "fodo"
$target = "food"
Output: true
Example 4:
Input: $source = "feed"
$target = "feed"
Output: true
#! /usr/bin/env raku
unit sub MAIN ($source where $source.chars > 0, # [1]
$destination where $destination.chars > 0, # [2]
:v(:$verbose));
if $destination.chars != $source.chars # [3]
{
say ": Different string lengths; { $source.chars } vs \
{ $destination.chars }" if $verbose;
say False; # [3a]
}
else
{
my @pairs = $source.comb Z $destination.comb; # [4]
say ": Pairs: { @pairs.raku }" if $verbose;
my @changes = @pairs.grep({ $_[0] ne $_[1] }); # [5]
say ": Pairs with changes: { @changes.raku }" if $verbose;
if @changes.elems == 2 # [6]
{
say @changes[0][0] eq @changes[1][1] &&
@changes[1][1] eq @changes[0][0]; # [7]
}
else
{
say ": Not two pairs of letters that differ, got { @changes.elems}"
if $verbose;
say False; # [8]
}
}
[1,2] The two strings, with at least 1 character in each.
[2] We could have changed the constraint to
where $destination.chars == $source.chars
, but the program should print
False
in that case - so we it in [3] instead.
[3] Different length of the two strings? If so, say False
.
[4] Split the two strinmgs into into individual characters (with
comb
), and zip the two arrays together like a DNA Helix with the infix
Z
(zipper) operator. The result is an array consisting of subarrays with
two elements, one each from source and destination.
See docs.raku.org/routine/Z for more information about Z
.
[5] Use grep
to keep only the elements (subarrays) where the two values
differ.
[6] Have we changed exactly two characters?
[7] Have we swapped both of them with eachother? Print true
if we have,
and False
if not.
[8] Not swapped exactly two characters, then print False
as we need
exactly 2 swappings.
Running it:
$ ./buddy-strings fuck fcuk
True
$ ./buddy-strings love love
False
$ ./buddy-strings -fodo food
True
$ ./buddy-strings feed feed
False
Looking good, except the last one. (So, no. Not actually looking good at all...)
Let us do it with verbose mode before looking into the problem:
$ ./buddy-strings -v fuck fcuk
: Pairs: [("f", "f"), ("u", "c"), ("c", "u"), ("k", "k")]
: Pairs with changes: [("u", "c"), ("c", "u")]
True
$ ./buddy-strings -v love love
: Pairs: [("l", "l"), ("o", "o"), ("v", "v"), ("e", "e")]
: Pairs with changes: []
: Not two pairs of letters that differ, got 0
False
$ ./buddy-strings -v fodo food
: Pairs: [("f", "f"), ("o", "o"), ("d", "o"), ("o", "d")]
: Pairs with changes: [("d", "o"), ("o", "d")]
True
$ ./buddy-strings -v feed feed
: Pairs: [("f", "f"), ("e", "e"), ("e", "e"), ("d", "d")]
: Pairs with changes: []
: Not two pairs of letters that differ, got 0
False
The idea is that we can swap the first «e» with the second «e». That is not so hard to program:
File: buddy-strings-ok
#! /usr/bin/env raku
unit sub MAIN ($source where $source.chars > 0,
$destination where $destination.chars > 0,
:v(:$verbose));
if $destination.chars != $source.chars
{
say ": Different string lengths; { $source.chars } vs \
{ $destination.chars }" if $verbose;
say False;
}
else
{
my @pairs = $source.comb Z $destination.comb;
say ": Pairs: { @pairs.raku }" if $verbose;
my @changes = @pairs.grep({ $_[0] ne $_[1] });
say ": Pairs with changes: { @changes.raku }" if $verbose;
if @changes.elems == 2
{
say @changes[0][0] eq @changes[1][1] &&
@changes[1][1] eq @changes[0][0];
}
elsif @changes.elems == 0 && $source.comb.repeated.elems # [1]
{
say ": Identical strings, but we can swap duplicates" if $verbose;
say True; # [1a]
}
else
{
say ": Not two pairs of letters that differ, got { @changes.elems }"
if $verbose;
say False;
}
}
[1] No swappings (of different characters), but we have repeated
characters (with repeated
) in one of the strings (actually both, as they
are equal). With at least one duplicate, we can swap the original one and that
duplicate and succeed; print Trrue
[1a].
See docs.raku.org/routine/repeated for more information about repeated
.
Running it with verbose mode:
$ ./buddy-strings-ok -v fuck fcuk
: Pairs: [("f", "f"), ("u", "c"), ("c", "u"), ("k", "k")]
: Pairs with changes: [("u", "c"), ("c", "u")]
True
$ ./buddy-strings-ok -v love love
: Pairs: [("l", "l"), ("o", "o"), ("v", "v"), ("e", "e")]
: Pairs with changes: []
: Not two pairs of letters that differ, got 0
False
$ ./buddy-strings-ok -v fodo food
: Pairs: [("f", "f"), ("o", "o"), ("d", "o"), ("o", "d")]
: Pairs with changes: [("d", "o"), ("o", "d")]
True
$ ./buddy-strings-ok -v feed feed
: Pairs: [("f", "f"), ("e", "e"), ("e", "e"), ("d", "d")]
: Pairs with changes: []
: Identical strings, but we can swap duplicates
True
Some more, just for fun:
$ ./buddy-strings-ok -v aaaa aaaa
: Pairs: [("a", "a"), ("a", "a"), ("a", "a"), ("a", "a")]
: Pairs with changes: []
: Identical strings, but we can swap duplicates
True
$ ./buddy-strings-ok -v abcd abcd
: Pairs: [("a", "a"), ("b", "b"), ("c", "c"), ("d", "d")]
: Pairs with changes: []
: Not two pairs of letters that differ, got 0
False
And that's it.