The Odyssey — A Roman Coding Adventure

Michael Gallipo
4 min readMay 28, 2018

Sure the original “Odyssey” was written by a Greek poet, but the Romans appropriated freely from their Mediterranean siblings and I feel no shame in doing the same. Over the course of my career I have written a lot — newsletters, mass-distribution emails, etc. But in almost all of those cases, I was comfortable in the knowledge that I knew more (or at least as much) about my subject material as any of my likely readers. This will almost certainly not be the case with this blog, so in that sense, it’s venturing into new territory. So I will just need to embrace the saying emblazoned on the front of one my t-shirts “Everything I say is fully substantiated by my own opinion!”

Why Coding?

Perhaps a little background is in order before getting to the story. Although I had some early experience with computers (took my first programming class at age 11), I have spent most of my career in money management. In many ways, it was very enjoyable. Because almost any event could impact my work, I never knew what any day might bring. But that also meant that almost everything was open-ended. But with coding, while there may be multiple ways to accomplish something (more on that to come), at the end of the day, your code works or it doesn’t. Full stop. The challenge inherent in that appeals greatly to the kid who loved geometry proofs in school or who got a perfect score on the logic games portion of the LSATs.

Whiteboarding

As part of our bootcamp training, we are introduced to the soft skills needed to succeed in our new profession. The other day, we were introduced to technical interviews and taught a process to whiteboard algorithms. During this process, our instructor talked about one of her technical interviews where she had to devise an algorithm to convert regular numbers to Roman numerals. And thus, a seed was planted.

The next day, while I mulled over some of the other problems in our example set, I couldn’t get the Roman numeral problem out of my head. In the midst of other activities, I kicked it around in my head.

Solving it — the first time

The first step to solving was realizing that the Romans treated each column in our numbering system separately. Thus a number ending in 9 will always end in IX whether its 9, 19, 129 or 1099. The logic within each column is the same, only the letters change. For ex., the logic behind XXX (30) is the same as III (3).

From there the key items were to figure out how many digits the number was and be able to extract each digit individually. I then used a series of if/elsif’s to determine the “Roman” value of each digit and add each segment to the result string. One small section of the code (dealing with the hundreds column) appears below:

if @number.to_i > 99
if hundreds_digit == 0
elsif hundreds_digit < 4
hundreds_digit.times do
roman_numeral += "C"
end
elsif hundreds_digit == 4
roman_numeral += "CD"
elsif hundreds_digit < 9
roman_numeral += "D"
if hundreds_digit > 5
(hundreds_digit - 5).times do
roman_numeral += "C"
end
end
else
roman_numeral += "CM"
end
else
end

After a little bit of debugging I was thrilled that the code worked. At my instructor’s suggestion, I shared it with the group. A while later she came back with, “Great. Now how about Step 7? How would you refactor it?” I stared at the screen for a few minutes, perhaps muttering a couple of NSFW phrases to myself, thinking to myself, refactor? I just barely solved it and got it to work. How the heck am I going to change anything? If I had any better ideas, that’s what I would have done to begin with. Having completed another tricky (for me at least) exercise in the interim, I was pretty fried and decided to call it a night.

Solving it…. again

The next day, I thought about the problem again. And thought about the logic I had used to break it down initially. I kept coming back to the part about the logic of each column being the same. That sounds an awful lot like something a loop is good for. Then I thought why not create an array akin to a lookup table. I could use the column I was in as one index variable and the actual digit of that column as the second. With that insight, my nearly 100 lines of code became 24 (presented in their entirety below).

def roman_numeral(number)
@number = number.to_s
length = @number.length
roman_numeral = ""
roman_array = [["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"], ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"], ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"], ["", "M", "MM", "MMM", "MMMM"]]i = 0
length.times do
i2 = @number[length - (i + 1)].to_i
roman_digit = roman_array[i][i2]
roman_numeral.insert(0, roman_digit)
i += 1
end
if roman_numeral == ""
puts "The Romans did not have the concept of zero as a number but used the word nulla"
else
puts roman_numeral
end
endroman_numeral(2018) # => MMXVIII

The takeaway from this exercise for me is that there is almost always a better, more efficient, more elegant way to do something. Just because something works, doesn’t mean it can’t be improved. Just like Roman numerals themselves.

--

--