• "Roman Numerals" Review

The Republic, Julius Caesar, The Colosseum. Yes, I'm talking about Ancient Rome. A few days ago I read Conn Iggulden's book about Caesar successor, Octavian and remembered the CheckiO mission "Roman Numerals". So let's look revisit this numeral system.

Roman numerals come from the ancient Roman numbering system. They are based on specific letters of the alphabet which are combined to signify the sum (or, in some cases, the difference) of their values. The first ten Roman numerals are:

I, II, III, IV, V, VI, VII, VIII, IX, X

The Roman numeral system is decimal based, but not directly positional and does not include a zero. Roman numerals are based on combinations of these seven symbols:

Roman-numerals

Simple Solution

We can single out "elemental" numbers and break the given number at these elements top down. Here is those "elements" for the roman numerals:

"M" 1000, "CM" 900,
"D"  500, "CD" 400,
"C"  100, "XC"  90,
"L"   50, "XL"  40,
"X"   10, "IX"   9,
"V"    5, "IV"   4,
"I"    1

Next we try to subtract these numbers from the given until we can. And connect characters from left to right. The result is our number in roman form.

ELEMENTS = (("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
            ("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
            ("X", 10), ("IX", 9), ("V", 5), ("IV", 4), ("I", 1))


def checkio(number):
    result = ""
    for roman, n in ELEMENTS:
        if n <= number:
            result += roman * (number // n)
            number %= n
    return result

"Clear" Solutions

In the "Clear" category, @JulianNicholls's "First" solution has earned many player votes and uses simple clear algorithm.

The next is Mark Pilgrim's realisation written by @macfreek. This solution is like the previous one but with comments and other "production" features.

"Creative" solutions (just for fun)

How about a veeeery long one-liner from @ciel?

checkio=lambda data: ['','M','MM','MMM'][data//1000]+['','C','CC','CCC','CD','D','DC','DCC','DCCC','CM'][data//100%10]+['','X','XX','XXX','XL','L','LX','LXX','LXXX','XC'][data//10%10]+['','I','II','III','IV','V','VI','VII','VIII','IX'][data%10]

Or "Recursive, short, weird but works! :)" by @hrvoje.

def checkio(data):
    s = lambda b,z: '' if not z else str(s(b%z[0][0], z[1:])) + (b//z[0][0])*z[0][1]    
    return s(data, [(1000, 'M'), (900, 'MC'), (500, 'D'), (400, 'DC'), (100, 'C'), (90, 'CX'), (50, 'L'), (40, 'LX'), (10, 'X'), (9, 'XI'), (5, 'V'), (4, 'VI'), (1, 'I')])[::-1]

Or even the puzzler "dict FTW" from @veky instead of a weekend crossword for you.

def checkio(x):
    a,r="",{}
    for i in range(3):
        p,(j,c,d)=10**i,"IVXLCDM"[2*i:][:3]
        r.update({p:j,5*p:c,4*p:j+c,9*p:j+d,10*p:d})
    for k in reversed(sorted(r)):
        a+=x//k*r[k]
        x%=k
    return a

That's all folks. Maybe you would like to review some CiO mission?

Valentin Bryukhanov aka Bryukh

Welcome to CheckiO - games for coders where you can improve your codings skills.

The main idea behind these games is to give you the opportunity to learn by exchanging experience with the rest of the community. Every day we are trying to find interesting solutions for you to help you become a better coder.

Join the Game