with Raku

This is my response to The Weekly Challenge #174.

Write a script to generate first

A disarium number is an integer where the sum of each digit raised to the power of its position in the number, is equal to the number.

For example:

`19 Disarium Numbers`

.
A disarium number is an integer where the sum of each digit raised to the power of its position in the number, is equal to the number.

For example:

518 is a disarium number as (5 ** 1) + (1 ** 2) + (8 ** 3) => 5 + 1 + 512 => 518

This sequence is available as oeis.org/A032799 - elbeit without using the name «Disarium Numbers».

File: disarium-sequence#! /usr/bin/env raku
unit sub MAIN (Int $count where $count > 0 = 19); # [1]
my $ds := (^Inf).grep( *.&is-disarium ); # [2]
say $ds[^$count].join(", "); # [3]
sub is-disarium ($number) # [2a]
{
my $position = 0; # [4]
my $sum = 0; # [5]
for $number.comb -> $digit # [6]
{
$sum += $digit ** ++$position; # [7]
}
return $sum == $number; # [8]
}

[1] The number of values to print, as a positive integer, with 19 as default.

[2] The sequence, starting with all non-negative integers, and applying `grep`

to keep the disarium numbers only.

[3] Print the requested number of values.

[4] The position, as we need this in the calculation. The first one has position 1, and not zero (the offset). I have compensated for this with the prefix incrementation in [7]

[5] The total sum.

[6] For each digit,

[7] • add the sum of that digit (raised to the power of the position).

[8] Do we have a match (i.e. the sum is the same as the number)?

Running it:

$ ./disarium-sequence 19
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 89, 135, 175, 518, 598, 1306, 1676, 2427, \
2646798

We got the same sequence as OEIS (see link above), so we are good.

You are given a list of integers with no duplicates, e.g.

Write two functions,

File: permutation-ranking
`[0, 1, 2]`

.
Write two functions,

`permutation2rank()`

which will take the list and
determine its rank (starting at 0) in the set of possible permutations arranged in
lexicographic order, and `rank2permutation()`

which will take the list
and a rank number and produce just that permutation.
Please checkout this post for more informations and algorithm.

Given the list`[0, 1, 2]`

the ordered permutations are:
0: [0, 1, 2]
1: [0, 2, 1]
2: [1, 0, 2]
3: [1, 2, 0]
4: [2, 0, 1]
5: [2, 1, 0]

and therefore:
permutation2rank([1, 0, 2]) = 2
rank2permutation([0, 1, 2], 1) = [0, 2, 1]

#! /usr/bin/env raku
unit sub MAIN (*@i where all(@i) ~~ Int && ! @i.repeated, # [1]
:$r, :v(:$verbose)); # [1a]
say permutation2rank(@i); # [2]
say rank2permutation(@i, $r); # [6]
sub permutation2rank(@list) # [2a]
{
my @p = @list.sort.permutations; # [3]
for ^@p.elems -> $index # [4]
{
say ": $index -> @p[$index]" if $verbose;
return $index if @p[$index] cmp @list == 0; # [5]
}
}
sub rank2permutation(@list, $index) # [6a]
{
my @p = @list.sort.permutations; # [7]
return @p[$index]; # [8]
}

[1] The `all`

Juntion is used to enforce
that all the arguments are integers, and the `repeated`

is used
to ensure that they are unique. The function returns any duplictes, and
negating that list gives the desired result. Note the use of a named argument
(`:$r`

) to specify the rank value [1a].

[2] Give us the rank.

[3] We start with the permutations, after sorting the list so that we get them in the correct order.

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

.

[4] Iterate over the index of the permutations.

[5] Return the index if we have found the correct version of the list.
Note the use of `cnp`

to smart match two objects. The return value is 0 (when
coerced to a numeric value, as done here) if they are equal.

See
docs.raku.org/routine/cmp
for more information about the Generic, "smart" three-way comparator
`cmp`

.

[6] Get the permutation with the given rank.

[7] The same as [3].

[8] Look it up with the index - which is the same as the rank.

Running it:

$ ./permutation-ranking -r=1 1 0 2
2
(0 2 1)

Looking good.

And that's it.