by Arne Sommer

# Disarmed Ranking with Raku

 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); #  my \$ds := (^Inf).grep( *.&is-disarium ); #  say \$ds[^\$count].join(", "); #  sub is-disarium (\$number) # [2a] { my \$position = 0; #  my \$sum = 0; #  for \$number.comb -> \$digit #  { \$sum += \$digit ** ++\$position; #  } return \$sum == \$number; #  } ```

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

 The sequence, starting with all non-negative integers, and applying `grep` to keep the disarium numbers only.

 Print the requested number of values.

 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 

 The total sum.

 For each digit,

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

 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, #  :\$r, :v(:\$verbose)); # [1a] say permutation2rank(@i); #  say rank2permutation(@i, \$r); #  sub permutation2rank(@list) # [2a] { my @p = @list.sort.permutations; #  for ^@p.elems -> \$index #  { say ": \$index -> @p[\$index]" if \$verbose; return \$index if @p[\$index] cmp @list == 0; #  } } sub rank2permutation(@list, \$index) # [6a] { my @p = @list.sort.permutations; #  return @p[\$index]; #  } ```

 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].

 Give us the rank.

 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`.

 Iterate over the index of the permutations.

 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`.

 Get the permutation with the given rank.

 The same as .

 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.