with Raku

This is my response to The Weekly Challenge #245.

You are given two array of languages and its popularity.

Write a script to sort the language based on popularity.

Example 1:

File: sort-language
Write a script to sort the language based on popularity.

Example 1:

Input: @lang = ('perl', 'c', 'python')
@popularity = (2, 1, 3)
Output: ('c', 'perl', 'python')

Example 2:
Input: @lang = ('c++', 'haskell', 'java')
@popularity = (1, 3, 2)
Output: ('c++', 'java', 'haskell')

#! /usr/bin/env raku
unit sub MAIN (
$popularity, # [1]
*@lang where @lang.elems == $popularity.words.elems > 0, # [2]
&& $popularity.words.repeated.elems == 0 # [2a]
&& $popularity.words.min == 1 # [2b]
&& $popularity.words.max == $popularity.words.elems, # [2c]
:v(:$verbose)
);
my @popularity = $popularity.words>>.Int; # [3]
my %popularity; # [4]
for ^@popularity -> $index # [5]
{
%popularity{@lang[$index]} = @popularity[$index]; # [6]
say ": Language '{ @lang[$index] } with popularity { @popularity[$index] }" if $verbose;
}
my @output = @lang.sort({ %popularity{$^a} <=> %popularity{$^b} }); # [7]
say "(" ~ @output.map({ "'$_'" }).join(", ") ~ ")"; # [8]

[1] Specify the popularity as the first argument, a quoted space separated string.

[2] Followed by the languages. Note the check on the
number of languages (at least one), and the same number of them as given in
[1]. Then we check that they are all unique [2a] (by ensuring that there are
no duplicates (with `repeated`

), and that the first one has the
value 1 [2b], and the last one has the value of the length of the language
array - thus ensureing that all the popularity values are given.

[3] Split the popularity string (with `words`

), and coerce all
the resulting strings to integers (so that verbose mode looks nicer).

[4] We are going to build up the popularity here; the language as key, and the popularity number as value.

[5] Iterate over the indices for the polularity.

[6] Set up the mapping from the langue to the popularity.

[7] Sort the languages on their popularity.

[8] Pretty print the result.

Running it:

$ ./sort-language "2 1 3" perl c python
('c', 'perl', 'python')
$ ./sort-language "1 3 2" c++ haskell java
('c++', 'java', 'haskell')

Looking good.

With verbose mode:

$ ./sort-language -v "2 1 3" perl c python
: Language 'perl with popularity 2
: Language 'c with popularity 1
: Language 'python with popularity 3
('c', 'perl', 'python')
$ ./sort-language -v "1 3 2" c++ haskell java
: Language 'c++ with popularity 1
: Language 'haskell with popularity 3
: Language 'java with popularity 2
('c++', 'java', 'haskell')

You are given an array of integers >= 0.

Write a script to return the largest number formed by concatenating some of the given integers in any order which is also multiple of 3. Return -1 if none found.

Example 1:

File: largest-of-three
Write a script to return the largest number formed by concatenating some of the given integers in any order which is also multiple of 3. Return -1 if none found.

Example 1:

Input: @ints = (8, 1, 9)
Output: 981
981 % 3 == 0

Example 2:
Input: @ints = (8, 6, 7, 1, 0)
Output: 8760

Example 3:
Input: @ints = (1)
Output: -1

#! /usr/bin/env raku
unit sub MAIN (*@ints where @ints.elems >= 1 && all(@ints) ~~ UInt, # [1]
:v(:$verbose));
my $largest = -1; # [2]
for @ints.combinations(1..Inf) -> @combination # [3]
{
say ":Combination: @combination[]" if $verbose;
for @combination.permutations.unique(:with(&[eqv])) -> @permutation # [4]
{
my $candidate = @permutation.join; # [5]
my $is-three = $candidate %% 3; # [6]
if $is-three # [7]
{
$largest = max($largest, $candidate); # [7a]
say ": - Permutation: @permutation[] -> $candidate %% 3" if $verbose;
}
else
{
say ": - Permutation: @permutation[] -> $candidate" if $verbose;
}
}
}
say $largest; # [8]

[1] At last one element, and they must all be non negative integers (the UInt; Unsigned Int type).

[2] Initial value, and the result if we do not have any match(es). Any matching value will be higher.

[3] Use `combinations`

to get all the
combinations. Note the array slice to get rid of the first combination, as
that is an empty list

See docs.raku.org/routine/combinations for more information about `combinations`

.

[4] Iterate over all the permutations, and get rid
of duplicates (with `:with(&[eqv]`

) in case we had duplicates in the
input array.

See docs.raku.org/routine/permutations for more information about `permutations`

.

[5] Join the values together to form a single value.

[6] Is it divisible by 3? (Note the divisibility operator
`%%`

.)

See docs.raku.org/routine/%% for more information about the Divisibility Operator `%%`

.

[7] If yes, set the maximum value to the largest of this one
and the old value with `max`

[7a].

See docs.raku.org/routine/maxfor more information about `max`

.

[8] Pretty print the result.

Running it:

$ ./largest-of-three 8 1 9
981
$ ./largest-of-three 8 6 7 1 0
8760
$ ./largest-of-three 1
-1

Looking good.

With verbose mode, for the first example only:

$ ./largest-of-three -v 8 1 9
:Combination: 8
: - Permutation: 8 -> 8
:Combination: 1
: - Permutation: 1 -> 1
:Combination: 9
: - Permutation: 9 -> 9 %% 3
:Combination: 8 1
: - Permutation: 8 1 -> 81 %% 3
: - Permutation: 1 8 -> 18 %% 3
:Combination: 8 9
: - Permutation: 8 9 -> 89
: - Permutation: 9 8 -> 98
:Combination: 1 9
: - Permutation: 1 9 -> 19
: - Permutation: 9 1 -> 91
:Combination: 8 1 9
: - Permutation: 8 1 9 -> 819 %% 3
: - Permutation: 8 9 1 -> 891 %% 3
: - Permutation: 1 8 9 -> 189 %% 3
: - Permutation: 1 9 8 -> 198 %% 3
: - Permutation: 9 8 1 -> 981 %% 3
: - Permutation: 9 1 8 -> 918 %% 3
981

And that's it.