This is my response to The Weekly Challenge #195.
$n > 0
.
1
and $n
.
Input: $n = 15
Output: 14 as except 11 all other integers between 1 and 15 are spcial.
Example 2:
Input: $n = 35
Output: 32 as except 11, 22, 33 all others are special.
This resembles last week's
Frequency Equalizer (#194.2), with calculation
of character frequencies within a string. The Bag
approach is equally
suitable here:
unit sub MAIN (Int $n where $n > 0, :v(:$verbose)); # [1]
my $count = 0; # [2]
for 1 .. $n -> $candidate # [3]
{
my $special = is-special($candidate); # [4]
$count++ if $special; # [6]
say ": $candidate { "special" if $special }" if $verbose;
}
say $count; # [7]
sub is-special ($integer) # [5]
{
return all($integer.comb.Bag.values) == 1; # [5]
}
[1] Ensure that we get a positive integer.
[2] We are going to count the special integers, one at a time.
[3] Iterate over the values in the range (1 - upper limit).
[4] Is it a special integer?
[5]
Turn the number into a list of single characters (with comb
).
Then turn that list into a Bag
, a hash like structure where the values in the
input list is the keys, and the frequency of each element is the value. Then we use an
all
junction to ensure that all the frequencies (with values
)
are equal to 1.
See
docs.raku.org/type/Bag
for more information about the Bag
type.
See
docs.raku.org/routine/all
for more information about the all
Junction.
[6] Add to the counter, if it is special.
[7] Print the count.
Running it:
$ ./special-integers 15
14
$ ./special-integers 35
32
Looking good.
With verbose mode:
$ ./special-integers -v 15
: 1 special
: 2 special
: 3 special
: 4 special
: 5 special
: 6 special
: 7 special
: 8 special
: 9 special
: 10 special
: 11
: 12 special
: 13 special
: 14 special
: 15 special
14
$ ./special-integers -v 35
: 1 special
: 2 special
: 3 special
: 4 special
: 5 special
: 6 special
: 7 special
: 8 special
: 9 special
: 10 special
: 11
: 12 special
: 13 special
: 14 special
: 15 special
: 16 special
: 17 special
: 18 special
: 19 special
: 20 special
: 21 special
: 22
: 23 special
: 24 special
: 25 special
: 26 special
: 27 special
: 28 special
: 29 special
: 30 special
: 31 special
: 32 special
: 33
: 34 special
: 35 special
32
@list
.
smallest even integer
. For all
other case, return -1
.
Input: @list = (1,1,2,6,2)
Output: 2 as there are only 2 even numbers 2 and 6 and of those 2
appears the most.
Example 2:
Input: @list = (1,3,5,7)
Output: -1 since no even numbers found in the list
Example 3:
Input: @list = (6,4,4,6,1)
Output: 4 since there are only two even numbers 4 and 6. They both
appears the equal number of times, so pick the smallest.
#! /usr/bin/env raku
unit sub MAIN (*@list where @list.elems > 0 # [1]
&& all(@list) ~~ /^<[1..9]><[0..9]>*$/, :v(:$verbose));
my @even = @list.grep: * %% 2; # [2]
if @even.elems # [3]
{
my $bag = @even.Bag; # [4]
my $max = $bag.values.max; # [5]
my $res = $bag.grep({ $_.value == $max }); # [6]
my @sorted = $res>>.key.sort; # [7]
if $verbose
{
say ":Even: @even[]"; # [4a]
say ":Max: $max"; # [5a]
say ":Sorted: @sorted[]"; # [7a]
}
say @sorted.first; # [8]
}
else
{
say ":No even integers" if $verbose;
say -1; # [9]
}
[1] Ensure at least 1 element, and that all of them are positive integers.
[2] Get the even integers, using grep
and the divisibilty
operator %%
.
See
docs.raku.org/routine/%%
for more information about the Divisibility Operator %%
.
[3] Do we have any even elements at all?
[4] Turn the values into a Bag
.
[5] Get the highest frequency (the value
part of the Bag).
[6] Get the Bag entries with the highest frequency (as calculated in [5]). There may be more than one.
[7] Get all the keys (i.e. integers from @list
), applied individually on each
Bag entry (a Pair) with >>.key
, in sorted order.
[8] The first one in either the only one, or the lowest value.
[9] No even elements? Print «-1» and we are done.
Running it:
$ ./most-frequent-even 1 1 2 6 2
2
$ ./most-frequent-even 1 3 5 7
-1
$ ./most-frequent-even 6 4 4 6 1
4
Looking good.
With verbose mode:
$ ./most-frequent-even -v 1 1 2 6 2
:Even: 2 6 2
:Max: 2
:Sorted: 2
2
$ ./most-frequent-even -v 1 3 5 7
:No even integers
-1
$ ./most-frequent-even -v 6 4 4 6 1
:Even: 6 4 4 6
:Max: 2
:Sorted: 4 6
4
And that's it.