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.