by Arne Sommer

# Disarmed Ranking with Raku

[193] Published 23. July 2022.

This is my response to The Weekly Challenge #174.

## Challenge #174.1: Disarium Numbers

Write a script to generate first `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.

## Challenge #174.2: Permutation Ranking

You are given a list of integers with no duplicates, e.g. `[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.

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] ```
File: permutation-ranking ```#! /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.