Unique Rank
with Raku

by Arne Sommer

Unique Rank with Raku

[280] Published 14. March 2024.

This is my response to The Weekly Challenge #260.

Challenge #260.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
File: unique-occurences-bag
#! /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

Challenge #260.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
File: dictionary-rank
#! /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.