Perl Weekly Challenge: Week 260
Challenge 1:
Unique Occurrences
You are given an array of integers,
@ints
.Write a script to return 1 if the number of occurrences of each value in the given array is unique or 0 otherwise.
Example 1
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
In my Raku solution, the first thing I did was create a hash to store how many times each value was seen.
my %count;
Then I did the actual counting.
@ints.map({ %count{$_}++ });
If the total number of values seen is equal to the unique number of values seen, we print 1 otherwise we print 0.
say %count.values.elems == %count.values.unique.elems ?? 1 !! 0;
For the Perl version I once again had to reach into my archive of previous challenges; this time to find a replacement for
.unique()
. With that, it looks pretty similar to the Raku version.
my %count;
map { $count{$_}++ } @ints;
say scalar values %count == scalar unique([values %count]) ? 1 : 0;
Challenge 2:
Dictionary Rank
You are given a word,
$word
.Write a script to compute the dictionary rank of the given word.
Example 1
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
Raku can solve this in one slightly long line.
say %(@*ARGS[0].comb.permutations.map({$_.join}).sort.unique.kv.reverse){@*ARGS[0]} + 1
Starting from somewhere near the beginning, we get the word from the command line and split it into a list of characters with
.comb()
. Then we find all the permutations of that list with .permutations()
. We want strings not list so we join all those
permutation lists back with .map()
and .join()
. These strings are then sorted into dictionary order with .sort()
and duplicates are filtered out with .unique()
. At this point, we have a list of strings. .kv()
converts a list or array into key-value pairs where the value is an element of the list and the key is the index of the element in the list. .Hash
casts this list of pairs into a hash. But this hash is backwards for our purposes; we want to be able to look up the index based on the word not the other way around so we call .reverse()
which makes keys values and values keys. I wrapped up this whole statement in %( ... )
. This treats the key-value list as a hash. Now we can use the standard hash {}
syntax to look up the index of the word. One more slight problem though; array indexing starts from 0 but according to the spec, the rank should be 1-based. So we
have to add 1 to get the final answer.
For perl we need a unique()
replacement as in Challenge 1 and the permute()
function I have used in previous challenges.
my @permutations;
permute { push @permutations, \@_; } (split //, $word);
I need an explicit hash to store the dictionary ranks.
my %rank;
And then I can populate the hash with my permuted strings. The keys are the strings themselves, and the values are their index in the list of permutations.
my $index = 1;
for my $perm (sort (unique([map { join q{}, @{$_} } @permutations]))) {
$rank{$perm} = $index++;
}
Finally, I can look up the rank of the word and print it.
say $rank{$word};