with Raku

This is my response to The Weekly Challenge #220.

The Raku Conference Rīga, Latvia, August 3–4, 2023 |

You are given a list of words.

Write a script to return the list of common characters (sorted alphabetically) found in every word of the given list.

Example 1:

Write a script to return the list of common characters (sorted alphabetically) found in every word of the given list.

Example 1:

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")

You are given an array of integers, @ints.

An array is squareful if the sum of every pair of adjacent elements is a perfect square.

Write a script to find all the permutations of the given array that are squareful.

Example 1:

File: squareful
An array is squareful if the sum of every pair of adjacent elements is a perfect square.

Write a script to find all the permutations of the given array that are squareful.

Example 1:

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.