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.