My buddy Robert has been seeking new

opportunities in the software development realm, and recently ran into a coding

challenge that I haven’t thought about in a good long time: converting an

integer to Roman numeral.

Now, I actually hate these kinds of brain teasers in the context of interviewing

and hiring, but I do love to mess around with them from time to time. This one

was especially interesting to me because I have done it in the past and I

remember it being a fairly shoddy implementation that fell apart with higher

numbers.

That was then and this is now though. I had a rough idea in my head about how I

would want to approach the problem. Take the integer and break it up into

individual digits, then take those digits and convert them.

Previous attempts in the past (seriously, it’s been at least 10 or 15 years

since I attempted this) were for lack of a better word, clever. Attempting to

interrogate the numbers and attempt to “generate” a number. Take the number 8

for example, I remember at one point writing logic to determine that the number

“contained” 5 (or V) and then take the remaining integer and converting that to

III (3 * I).

Writing clever code is fun, but in my experience, rarely holds up. Fast forward

quite a ways into my software engineering career, being clever is something I

try to avoid unless it’s absolutely necessary. With this problem, I opted to

hard code a mapping of values that could exist in each of the places in the

number.

This resulted in an array of arrays broken out into 1-9, 10-90, 100-900 and

1,000-3,000.

I know what you’re thinking, “why only up to 3,000?” As it turns out, Roman

numerals only go up to 3,999. This was as per what the original spec for the

coding challenge said and I did take some liberties with looking it up on

Wikipedia to confirm.

My suspicion with my previous attempts falling apart were due to attempting to

convert values that were simply too large and should have been thrown own. Live

and learn.

So yeah, I went ahead and limited the conversion method to 1 through 3,999 and

went ahead and used TypeScript (which is my daily driver at this point) and

omitted any sort of run-time sanity checks on the argument coming in, simply

allowing TypeScript to do the type checking.

The only other liberty I took was in terms of fractions. Roman numerals do

support another block of letters / symbols to represent the fractions, but for

the sake of not over engineering, I didn’t venture down that path.

I did leave a note though. If this were in the context of me submitting a coding

challenge, I would want the person reviewing my code to know that I did give

that aspect of the conversion some thought, and consciously omitted it.

Here’s the code that I came up with:

```
const int2roman = (original: number): string => {
if (original < 1 || original > 3999) {
throw new Error('Error: Input integer limited to 1 through 3,999'
}
const numerals = [
['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'], // 1-9
['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'], // 10-90
['C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'], // 100-900
['M', 'MM', 'MMM'], // 1000-3000
// TODO: Could expand to support fractions, simply rounding for now
const digits = Math.round(original).toString().split(''
let position = (digits.length - 1
return digits.reduce((roman, digit) => {
if (digit !== '0') {
roman += numerals[position][parseInt(digit) - 1
}
position -= 1
return roman
}, ''
}
```

How do I know it works? Glad you asked! I scoured the web and found a listing of

Roman numeral values from 1 to 3,999 and I put together a quick test to run

through every time value, to see if my code generated the expected value.

Everything married up perfectly, and without any additional tweaks. With age

comes wisdom and all of that, and the lack of cleverness payed off.

Don’t get me wrong, I could have probably “golfed” the answer a bit to reduce

it’s size, but it’s pretty easy to read. Similar to being too clever, I’ll take

longer code that’s easier to read over cryptic one line solutions any day of the

week.