ðŸ“˜ Convert to Roman numerals using Perl 6

# ðŸ“˜ Convert to Roman numerals using Raku

N. B. Perl 6 has been renamed to Raku. Click to read more.

Convert an integer number to a Roman numerals string.

Roman numbers are not a direct translation of the decimal system. In this task, we assume that the number is not morethan 3999, which is the maximum a regular Roman number can reach.

Letâ€™s use the algorithm that keeps the table of pre-calculated sequences of Roman letters so that we donâ€™t have to check when III becomes IV, or when another I appears after V, etc.

In the program below, there areÂ foursuch sequences: for thousands, hundreds, tens, and ones. The program iterates over the digits of the number in the decimal representation and chooses one of the values from the array of lists stored in theÂ `@roman` variable.

`my \$n = 2018;my \$roman;my @roman =     1000 => < M MM MMM >,    100 => < C CC CCC CD D DC DCC DCCC CM >,    10  => < X XX XXX XL L LX LXX LXXX XC >,    1   => < I II III IV V VI VII VIII IX >;for @roman -> \$x {    my \$digit = (\$n / \$x.key).Int;     \$roman ~= \$x.value[\$digit - 1] if \$digit;    \$n %= \$x.key;}say \$roman; # MMXVIII`

Let us examine the structure of theÂ `@roman` container. In the program code, it looks like a hash. Indeed, it could be a hash, but in our case, the algorithm requires division by 1000, 100, and 10, so it is easier to organise data so that they are already sorted in the correct order.

TheÂ `< >` quotation construct in the program is the simplest way to create a list from the strings that do not contain spaces.Â If you print it with theÂ `say @roman` instruction, youâ€™ll get the following:

`[1000 => (M MM MMM) 100 => (C CC CCC CD D DC DCC DCCC CM) 10 => (X XX XXX XL L LX LXX LXXX XC) 1 => (I II III IV V VI VII VIII IX)]`

On the top level, it is a list of pairs, such asÂ `1000 => (M MM MMM)`. Pairs, or objects of theÂ `Pair` class, have theÂ `key` andÂ `value` methods .For the shown example of a pair, theÂ `key` method returnsÂ `1000`, and theÂ `value` method returns a listÂ `(M MM MMM)`.

The digits of the input numberÂ `\$n` are scanned from left to right:

`my \$digit = (\$n / \$x.key).Int;`

The value ofÂ `\$n` also becomes smaller and smaller at each step:

\$n %= \$x.key;

At each iteration, the next digit lands in theÂ `\$digit` variable, and it is used as the index that selects the correct Roman representation:

`\$roman ~= \$x.value[\$digit - 1] if \$digit; `

As zeros in the decimal form have no correspondence to the Roman numbers, only non-zero values are taken. When the loop is over, theÂ `\$roman` variable contains the desired Roman string.

The opposite conversion is examined in Task 84,Â Decode Roman numerals.