This is my response to The Weekly Challenge #260.
@ints
.
Input: @ints = (1,2,2,1,1,3)
Output: 1
The number 1 occurred 3 times.
The number 2 occurred 2 times.
The number 3 occurred 1 time.
All occurrences are unique, therefore the output is 1.
Example 2:
Input: @ints = (1,2,3)
Output: 0
Example 3:
Input: @ints = (-2,0,1,-2,1,1,0,1,-2,9)
Output: 1
#! /usr/bin/env raku
unit sub MAIN (*@ints where all(@ints) ~~ Int && @ints.elems > 0, # [1]
:v(:$verbose));
my @freq = @ints.Bag.values; # [2]
say ": Frequencies: @freq[]" if $verbose;
say @freq.repeated ?? 0 !! 1; # [3]
[1] All the arguments, of which there must be at least one, must be integers.
[2]
Turn the array into a Bag
, a hash like structure where
the original data are the keys and the original frequency are the values.
Then we use values
to get a list of frequencies.
See docs.raku.org/routine/Bag for more information about Bag
.
See docs.raku.org/routine/values for more information about values
.
[3] repeated
will give us a list of values that occur
more than once. Thus we print 1 if all the occurrences are unique and 0
otherwise.
See docs.raku.org/routine/repeated for more information about repeated
.
Running it:
$ ./unique-occurences 1 2 2 1 1 3
1
$ ./unique-occurences 1 2 3
0
$ ./unique-occurences -- -2 0 1 -2 1 1 0 1 -2 9
1
The --
is there to halt the parsing of command line options,
as -2
will be treated as an option otherwise.
Looking good.
With verbose mode:
$ ./unique-occurences -v 1 2 2 1 1 3
: Frequencies: 1 3 2
1
$ ./unique-occurences -v 1 2 3
: Frequencies: 1 1 1
0
$ ./unique-occurences -v -- -2 0 1 -2 1 1 0 1 -2 9
: Frequencies: 4 3 2 1
1
$word
.
Input: $word = 'CAT'
Output: 3
All possible combinations of the letters:
CAT, CTA, ATC, TCA, ACT, TAC
Arrange them in alphabetical order:
ACT, ATC, CAT, CTA, TAC, TCA
CAT is the 3rd in the list.
Therefore the dictionary rank of CAT is 3.
Example 2:
Input: $word = 'GOOGLE'
Output: 88
Example 3:
Input: $word = 'SECRET'
Output: 255
#! /usr/bin/env raku
unit sub MAIN ($word where $word.chars > 0, :v(:$verbose)); # [1]
my $perm = $word.comb.sort.permutations>>.join.unique; # [2]
say ": Permutations: $perm[]" if $verbose;
my $index = ($perm.grep: $word, :k).first; # [3]
say $index +1; # [4]
[1] Ensure at least one character in the word.
[2] Using permutations
on an array of characters
gives us all the ways we can combine them. If we sort the characters, then
the output will also be sorted. The result so far is an array of arrays.
We apply >>.join
the inner arrays, so that we end ut with words. The
unique
will get rid of duplicates, which we get if we have repeated
letters in the input string.
[3] Look for the given word in the array of permutations, using
grep
. Adding the :k
(keys) adverb gives us the keys instead of
the values themselves, and the key in an array context is the index. This
is an array, with one element, so we use first
to get it.
See docs.raku.org/routine/first for more information about first
.
[4] The rank starts with 1 as the first one, so we add 1 to the zero based index.
Running it:
$ ./dictionary-rank CAT
3
$ ./dictionary-rank GOOGLE
88
$ ./dictionary-rank SECRET
255
Looking good.
With verbose mode:
./dictionary-rank -v CAT
: Permutations: ACT ATC CAT CTA TAC TCA
3
$ ./dictionary-rank -v GOOGLE
: Permutations: EGGLOO EGGOLO EGGOOL EGLGOO ... OOGLGE OOLEGG OOLGEG OOLGGE
88
$ ./dictionary-rank -v SECRET
: Permutations: CEERST CEERTS CEESRT CEESTR ... TSEREC TSRCEE TSRECE TSREEC
I have abbreviated the verbose output for the second and third example.
And that's it.