I’ve been doing the Weekly
Challenges. The
latest
involved string splitting and testing. (Note that this ends today.)
Task 1: Last Word
You are given a string.
Write a script to find the length of last word in the given string.
Fairly straightforward: split by space, reject zero-length strings
(some splitters will include them and I can't say they're wrong), and
return the length of the last one.
Ruby:
def lastword(a)
Split and filter:
w = a.split(" ").select{|x| x.size > 0}
Find last string and take the length.
w[w.size - 1].size
end
Task 2: Buddy Strings
You are given two strings, source
and target
.
Write a script to find out if the given strings are Buddy Strings
.
If swapping of a letter in one string make them same as the other then they are
Buddy Strings.
This is where I find myself fighting with languages that say "oh, a
string is just an array of characters, no need to split it into an
array, you can just index into it". Yeah, you can index to read, but
very rarely to write; and the tutorials omit the splitting because
nobody needs to do that.
But Raku is not one such language. It doesn't have array comparisons,
though.
sub buddystrings($a, $b) {
Get a list of the characters in the first string.
my @ac = $a.comb;
Iterate over all possible pair indices.
for (0 .. @ac.elems - 2) -> $i {
for ($i + 1 .. @ac.elems - 1) -> $j {
Build a new list that's a copy of the old.
my @acx = $a.comb;
Swap the characters.
@acx[$i] = @ac[$j];
@acx[$j] = @ac[$i];
Compare with the original second string.
if (@acx.join("") eq $b) {
return True;
}
}
}
False;
}
Where I do have an array comparator, as in PostScript (OK I wrote it
myself):
/buddystrings {
0 dict begin
Split both strings to arrays.
s2a /bc exch def
s2a /ac exch def
My fallback result is false
.
false
Generate the pairs of indices.
0 1 ac length 2 sub {
/i exch def
i 1 add 1 ac length 1 sub {
/j exch def
Copy acx
directly from ac
, and put in the changed characters.
/acx ac deepcopy def
acx i ac j get put
acx j ac i get put
Do a deep value comparison.
acx bc deepeq {
If that was valid, dump the default false
and replace it with
true
.
pop true
exit
} if
} for
And if we have a true
, drop out of the outer loop too.
dup {
exit
} if
} for
end
} bind def
Full code on
github.