This is my response to The Weekly Challenge #220.
|
The Raku Conference Rīga, Latvia, August 3–4, 2023 |
Input: @words = ("Perl", "Rust", "Raku")
Output: ("r")
Example 2:
Input: @words = ("love", "live", "leave")
Output: ("e", "l", "v")
It follows from the first example that we should downcase the letters (i.e. convert them to lowercase).
File: common-characters
#! /usr/bin/env raku
unit sub MAIN (*@words where @words.elems > 1
&& all(@words) ~~ /^<[a..zA..Z]>+$/, # [1]
:v(:$verbose));
my $set = [(&)] @words>>.lc>>.comb; # [2]
# ###### # 2d # 2a # # 2b # 2c ###
say ":Set: { $set.raku }" if $verbose;
say '(' ~ $set.keys.sort.map({ '"' ~ $_ ~ '"' }).join(", ") ~ ')'; # [3]
[1] Ensure at least two words, all of which can only contain the standard 52 lower- and uppercase letters. (No messing around with things like Æ, ß, Ü or ð.)
[2]
We start with the words [2a], applying
lc on each one (with >>.lc) to coerce them to lowercase
[2b]. Then we apply comb on each word to coerce them into a list of
individual characters [2c]. The result so far is a list of lists. And finally we
use the intersection operator (&) - in combination with the
Reduction Metaoperator [] - to compute the common characters [2d].
The result is a (one) Set, courtesy of the reduction.
See
docs.raku.org/routine/(&),%20infix%20%E2%88%A9
for more information about the intersection operator (&).
See
docs.raku.org/type/Set
for more information about the Set type.
See
docs.raku.org/language/operators#Reduction_metaoperators for more
information about the Reduction Metaoperator [].
[3] We get the actual letters out of the Set object with the
keys method. The rest of this line is just pretty printing, in
sorted order.
Running it:
$ ./common-characters Perl Rust Raku
("r")
$ ./common-characters love live leave
("e", "l", "v")
Looking good.
With verbose mode, though it is not really helpful:
$ ./common-characters -v Perl Rust Raku
:Set: Set.new("r")
("r")
$ ./common-characters -v love live leave
:Set: Set.new("e","v","l")
("e", "l", "v")
Input: @ints = (1, 17, 8)
Output: (1, 8, 17), (17, 8, 1)
(1, 8, 17) since 1 + 8 => 9, a perfect square and also 8 + 17 => 25
is perfect square too.
(17, 8, 1) since 17 + 8 => 25, a perfect square and also 8 + 1 => 9
is perfect square too.
Example 2:
Input: @ints = (2, 2, 2)
Output: (2, 2, 2)
There is only one permutation possible.
#! /usr/bin/env raku
unit sub MAIN (*@ints where @ints.elems > 1 && all(@ints) ~~ Int); # [1]
my $length = @ints.elems; # [2]
my @squareful; # [3]
PERM-LOOP: # [4]
for @ints.permutations.unique(:with(&[eqv])) -> @permutation # [5]
{
for 0 .. $length -2 -> $index # [6]
{
my $sum = @permutation[$index] + @permutation[$index +1]; # [7]
my $root = $sum.sqrt; # [8]
next PERM-LOOP unless $root.Int == $root; # [9]
}
push(@squareful, @permutation); # [10]
}
say @squareful; # [11]
[1] At least two values, all of which must be integers.
[2] Get the number of values.
[3] The result (the squareful permutations) will end up here.
[4] We attach a label to this outer loop, as we need to reference it in [9].
[5] Iterate over the permutations (with
permutations), and then we get rid of duplicates (caused by duplicates
in the input list) with unique. We have to tell it how to compare
values, as the default behaviour does not cope with data structures, and
:with(&[eqv]) does just that; specifying the Equivalence Operator
eqv.
See
docs.raku.org/routine/eqv for more
information about the Equivalence Operator eqv.
[6] Iterate over the indices of the array, stopping at the last but one.
[7] Get the sum of values at the current index and the next one (index +1).
[8] Compute the square root.
[9] Skip this iteration of the outer loop (set up in [4], with next),
if the square root is not an integer (i.e. the number is not a perfect square).
[10] The inner loop completed without failing (in [9]) if we get here. Add the value to the result (as failure to fail is success, in this case).
[11] Print the result.
Running it:
$ ./squareful 1 17 8
[(1 8 17) (17 8 1)]
$ ./squareful 2 2 2
[(2 2 2)]
Looking good, except the formatting. But this is good enough, as I am short of time this week.
And that's it.