I’ve been doing the Weekly
Challenges. The
latest
involved joining strings and matching characters. (Note that this ends today.)
Task 1: Same String
You are given two arrays of strings.
Write a script to find out if the word created by concatenating the
array elements is the same.
Pretty straightforward in almost any language, even PostScript with my
extensions.
/samestring {
() strjoin exch
() strjoin
deepeq
} bind def
More conventionally in Ruby:
def samestring(a, b)
return a.join("") == b.join("")
end
Task 2: Consistent Strings
You are given an array of strings and allowed string having distinct
characters.
A string is consistent if all characters in the string appear in the
string allowed.
Write a script to return the number of consistent strings in the
given array.
The obvious algorithm is to test one character at a time, and bail out
if any of them isn't in the verification input. But most of the
languages I use have some kind of short-cut for this: Rust, Ruby, Raku
and Perl (via List::Utils
) each have an all
method on an interable
plus a test function which returns a boolean, and I'd already written
one for PostScript. Scala calls its all
and any
forall
and
exists
, and JavaScript calls them every
and some
, but they work
basically the same way. (Except Raku's. And Lua doesn't really like
the idea of iterables at all.)
This use of an all
function is not necessarily any more
efficient than writing out, as I often have for these things,
something along the lines of:
for n in items {
if !test(n) {
return false
}
}
return true
but it does mean that this kind of general-purpose workhorse code is
moved away into a different place from the important and task-specific
part, leaving the latter easier to comprehend.
So all the languages except Lua and Raku get something like this Rust:
fn consistentstrings(a: Vec<&str>, v: &str) -> u32 {
let vs = v.chars().collect::<HashSet<char>>();
a.iter().filter(|s| s.chars().unique().all(|c| vs.contains(&c))).count()
as u32
}
"For each string in a
, count it if each unique character in that
string exists in vs
; return the total count."
Raku's all
uses a junction structure which needs a somewhat
different approach. Where in most languages I'm doing something like
characters.all(|char| test(char))
Raku prefers
test(characters.all)
or in full
sub consistentstrings(@a, $v) {
my $vs = $v.comb.Set;
return @a.grep({$vs{$_.comb.Set.keys.all}:exists}).elems;
}
It's interestingly expressive, though I think it's pretty much unique
to this language.
Full code on
github.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.