This is my response to The Weekly Challenge #398.
Input: @arr = (18, 5, 7, 11)
Output: 18
18 is the only even number and divisible by 3.
Average: 18 / 1 = 18.
Example 2:
Input: @arr = (6, 12, 18, 24, 30, 40)
Output: 18
The qualifying numbers are 6, 12, 18, 24, and 30.
Average: (6 + 12 + 18 + 24 + 30) / 5 = 90 / 5 = 18
Example 3:
Input: @arr = (3, 9, 15, 21, 27)
Output: 0
None of the elements are even.
Since no elements qualify, return 0.
Example 4:
Input: @arr = (6, 12, 14, 20)
Output: 9
The qualifying numbers are 6 and 12.
Average: (6 + 12) / 2 = 9.
Example 5:
Input: @arr = (6, 6, 6, 12, 12)
Output: 8
All five numbers are even and divisible by 3.
Average: (6 + 6 + 6 + 12 + 12) / 5 = 8.4 => 8
This task is a cousin of «Absent Smallest Positive», the first part of last week's challenge. See Absent Reflection with Raku. Both programs are built around the mean of the array's elements. Last week, the mean of all elements served as a lower bound for the search for an absent positive integer; this time the array is first filtered to the even numbers divisible by 3, and the mean of the survivors is rounded to the closest integer.
File: divisible-average#! /usr/bin/env raku
unit sub MAIN (*@arr where @arr.elems > 0 && all(@arr) ~~ Int,
:v(:$verbose));
my @qualifying = @arr.grep: * %% 6;
if $verbose
{
for @arr -> $n
{
say ": $n " ~ (
$n %% 6
?? "is even and divisible by 3"
!! $n % 2
?? "is not even"
!! "is not divisible by 3"
);
}
say ": average is {@qualifying.sum / @qualifying.elems}"
if @qualifying;
}
say @qualifying.elems
?? (@qualifying.sum / @qualifying.elems).round
!! 0;
[3] Integers only, and we require at least one value.
[6] Get the qualifying values; integers divisible by 3. We use divisible by 6, as the result must be an integer - i.e. beeing divisible by two. Combining them is neat.
[23] Do we actually have any qualifying elements?
[24] If so, get the average value (the sum divided by the count)
and round it (with round).
See docs.raku.org/routine/round for more information about round.
[25] If not, print zero.
Running it:
$ ./divisible-average 18 5 7 11
18
$ ./divisible-average 6 12 18 24 30 40
18
$ ./divisible-average 3 9 15 21 27
0
$ ./divisible-average 6 12 14 20
9
$ ./divisible-average 6 6 6 12 12
8
Looking good.
With verbose mode:
$ ./divisible-average -v 18 5 7 11
: 18 is even and divisible by 3
: 5 is not even
: 7 is not even
: 11 is not even
: average is 18
18
$ ./divisible-average -v 6 12 18 24 30 40
: 6 is even and divisible by 3
: 12 is even and divisible by 3
: 18 is even and divisible by 3
: 24 is even and divisible by 3
: 30 is even and divisible by 3
: 40 is not divisible by 3
: average is 18
18
$ ./divisible-average -v 3 9 15 21 27
: 3 is not even
: 9 is not even
: 15 is not even
: 21 is not even
: 27 is not even
0
$ ./divisible-average -v 6 12 14 20
: 6 is even and divisible by 3
: 12 is even and divisible by 3
: 14 is not divisible by 3
: 20 is not divisible by 3
: average is 9
9
$ ./divisible-average -v 6 6 6 12 12
: 6 is even and divisible by 3
: 6 is even and divisible by 3
: 6 is even and divisible by 3
: 12 is even and divisible by 3
: 12 is even and divisible by 3
: average is 8.4
8
Input: @words = ("ab", "bc", "cd", "zy")
Output: "zy"
"ab" => [1 - 0] = [1]
"bc" => [2 - 1] = [1]
"cd" => [3 - 2] = [1]
"zy" => [24 - 25] = [-1]
Example 2:
Input: @words = ("cba", "fed", "azy")
Output: "azy"
"cba" => [1 - 2, 0 - 1] = [-1, -1]
"fed" => [4 - 5, 3 - 4] = [-1, -1]
"azy" => [25 - 0, 24 - 25] = [25, -1]
Example 3:
Input: @words = ("pop", "ada", "beb", "cfc")
Output: "pop"
"pop" => [14 - 15, 15 - 14] = [-1, 1]
"ada" => [3 - 0, 0 - 3] = [3, -3]
"beb" => [4 - 1, 1 - 4] = [3, -3]
"cfc" => [5 - 2, 2 - 5] = [3, -3]
Example 4:
Input: @words = ("aaaa", "zzzz", "mmmm", "aaba")
Output: "aaba"
"aaaa" => [0 - 0, 0 - 0, 0 - 0] = [0, 0, 0]
"zzzz" => [25 - 25, 25 - 25, 25 - 25] = [0, 0, 0]
"mmmm" => [12 - 12, 12 - 12, 12 - 12] = [0, 0, 0]
"aaba" => [0 - 0, 1 - 0, 0 - 1] = [0, 1, -1]
Example 5:
Input: @words = ("aceg", "bdfh", "cegi", "azbz")
Output: "azbz"
"aceg" => [2 - 0, 4 - 2, 6 - 4] = [2, 2, 2]
"bdfh" => [3 - 1, 5 - 3, 7 - 5] = [2, 2, 2]
"cegi" => [4 - 2, 6 - 4, 8 - 6] = [2, 2, 2]
"azbz" => [25 - 0, 1 - 25, 25 - 1] = [25, -24, 24]
#! /usr/bin/env raku
unit sub MAIN (*@words where @words.elems > 0
&& all(@words) ~~ /^ <[a..z]>**2..* $/
&& ( [==] @words>>.chars ),
:v(:$verbose));
my @signature = @words.map: { difference($_).raku };
my %count = @signature.Bag;
my $index = @signature.first: { %count{$_} == 1 }, :k;
if $verbose
{
for @words -> $word
{
say ": $word => { difference($word).raku }";
}
}
say @words[$index];
sub difference(Str $word)
{
my @codes = $word.ords;
my @diff = @codes[1..*] Z- @codes[0 ..^ @codes.elems - 1];
@diff;
}
[3] A slurpy array of words, consisting of lowercase letters only,
with at least one word, two letters in each word, and all the
words must have the same length (the [==] part).
[8] Get the difference arrays for all the words,
and stringifiy them with the raku method.
See docs.raku.org/routine/raku for more information about raku.
[9] Turn all the signature strings into a Bag, a hash like
structure with a frequency count.
[10] Get the index of the first signature that
occurs only once in the Bag. The :k adverb gives us the key
(or index) instead of the actual value.
See docs.raku.org/routine/first for more information about first.
[20] Print the word with this index.
[22] Procedure calculating the string difference.
[23] Convert the string into a list of unicode codepoints
with ords, the wholesale version of .ord.
See docs.raku.org/routine/ords for more information about ords.
See docs.raku.org/routine/ord for more information about ord.
[25] Compute the difference between each adjacent pair of
letters, using the infix meta operator Z with minus to get the
difference of the two values we "zip" together.
See docs.raku.org/routine/Z for more information about Z.
[26] Return the list of diffrences.
Running it:
$ ./string-difference ab bc cd zy
zy
$ ./string-difference cba fed azy
azy
$ ./string-difference pop ada beb cfc
pop
$ ./string-difference aaaa zzzz mmmm aaba
aaba
$ ./string-difference aceg bdfh cegi azbz
azbz
Looking good.
With verbose mode:
$ ./string-difference -v ab bc cd zy
: ab => [1]
: bc => [1]
: cd => [1]
: zy => [-1]
zy
$ ./string-difference -v cba fed azy
: cba => [-1, -1]
: fed => [-1, -1]
: azy => [25, -1]
azy
$ ./string-difference -v pop ada beb cfc
: pop => [-1, 1]
: ada => [3, -3]
: beb => [3, -3]
: cfc => [3, -3]
pop
$ ./string-difference -v aaaa zzzz mmmm aaba
: aaaa => [0, 0, 0]
: zzzz => [0, 0, 0]
: mmmm => [0, 0, 0]
: aaba => [0, 1, -1]
aaba
$ ./string-difference -v aceg bdfh cegi azbz
: aceg => [2, 2, 2]
: bdfh => [2, 2, 2]
: cegi => [2, 2, 2]
: azbz => [25, -24, 24]
azbz
And that's it.