I\'m trying to write a code that converts a user-inputted integer into its Roman numeral equivalent. What I have so far is:
The point of the generate_
This is my recursive function approach to convert a number to its roman equivalent
def solution(n):
# TODO convert int to roman string
string=''
symbol=['M','D','C','L','X','V','I']
value = [1000,500,100,50,10,5,1]
num = 10**(len(str(n))-1)
quo = n//num
rem=n%num
if quo in [0,1,2,3]:
string=string+symbol[value.index(num)]*quo
elif quo in [4,5,6,7,8]:
tem_str=symbol[value.index(num)]+symbol[value.index(num)-1]
+symbol[value.index(num)]*3
string=string+tem_str[(min(quo,5)-4):(max(quo,5)-3)]
else:
string=string+symbol[value.index(num)]+symbol[value.index(num)-2]
if rem==0:
return string
else:
string=string+solution(rem)
return string
print(solution(499))
print(solution(999))
print(solution(2456))
print(solution(2791))
CDXCIX
CMXCIX
MMCDLVI
MMDCCXCI
I was working through this conversion as a kata exercise, and I came up with a solution that takes advantage of Python's string operations:
from collections import namedtuple
Abbreviation = namedtuple('Abbreviation', 'long short')
abbreviations = [
Abbreviation('I' * 1000, 'M'),
Abbreviation('I' * 500, 'D'),
Abbreviation('I' * 100, 'C'),
Abbreviation('I' * 50, 'L'),
Abbreviation('I' * 10, 'X'),
Abbreviation('I' * 5, 'V'),
Abbreviation('DCCCC', 'CM'),
Abbreviation('CCCC', 'CD'),
Abbreviation('LXXXX', 'XC'),
Abbreviation('XXXX', 'XL'),
Abbreviation('VIIII', 'IX'),
Abbreviation('IIII', 'IV')
]
def to_roman(arabic):
roman = 'I' * arabic
for abbr in abbreviations:
roman = roman.replace(abbr.long, abbr.short)
return roman
I like its simplicity! No need for modulo operations, conditionals, or multiple loops. Of course, you don't need namedtuple
s either; you can use plain tuples or lists instead.
A KISS version of Manhattan's algorithm, without any "advanced" notion such as OrderedDict
, recursion, generators, inner function and break
:
ROMAN = [
(1000, "M"),
( 900, "CM"),
( 500, "D"),
( 400, "CD"),
( 100, "C"),
( 90, "XC"),
( 50, "L"),
( 40, "XL"),
( 10, "X"),
( 9, "IX"),
( 5, "V"),
( 4, "IV"),
( 1, "I"),
]
def int_to_roman(number):
result = ""
for (arabic, roman) in ROMAN:
(factor, number) = divmod(number, arabic)
result += roman * factor
return result
A prematurate exit could be added as soon as number
reaches zero, and the string accumulation could be made more pythonic, but my goal here was to produce the requested basic program.
Tested on all integers from 1 to 100000, which ought to be enough for anybody.
EDIT: the slightly more pythonic and faster version I alluded to:
def int_to_roman(number):
result = []
for (arabic, roman) in ROMAN:
(factor, number) = divmod(number, arabic)
result.append(roman * factor)
if number == 0:
break
return "".join(result)
Interesting question. Several approaches but haven't seen this one yet. We can trade execution time for memory, and reduce potential for pesky arithmetic errors (off-by-one, int vs float div, etc).
Each arabic digit (1s, 10s, 100s, etc) translates to a unique Roman sequence. So just use a lookup table.
ROMAN = {
0 : ['', 'm', 'mm', 'mmm'],
1 : ['', 'c', 'cc', 'ccc', 'cd', 'd', 'dc', 'dcc', 'dccc', 'cm'],
2 : ['', 'x', 'xx', 'xxx', 'xl', 'l', 'lx', 'lxx', 'lxxx', 'xc'],
3 : ['', 'i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii', 'viii', 'ix'],
}
def to_roman (num, lower = True):
'''Return the roman numeral version of num'''
ret = ''
digits = '%04d' % num
for pos, digit in enumerate (digits):
ret += ROMAN [pos] [int (digit)]
return lower and ret or ret.upper ()
You can add checks for 0 > num > 4000, but not necessary as lookup will fail on int conversion for '-' or index out of range. I prefer lowercase, but upper available as well.
Digit selection could be done arithmetically, but algorithm becomes a bit trickier. Lookups are simple and effective.
The code for this roman numeral does not check for errors like wrong letters it is just for a perfect roman numeral letters
roman_dict = {'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}
roman = input('Enter the roman numeral: ').upper()
roman_initial = roman # used to retain the original roman figure entered
lst = []
while roman != '':
if len(roman) > 1:
check = roman[0] + roman[1]
if check in roman_dict and len(roman) > 1:
lst.append(check)
roman = roman[roman.index(check[1])+1:]
else:
if check not in roman_dict and len(roman) > 1:
lst.append(check[0])
roman = roman[roman.index(check[0])+1:]
else:
if len(roman)==1:
check = roman[0]
lst.append(check[0])
roman = ''
if lst != []:
Sum = 0
for i in lst:
if i in roman_dict:
Sum += roman_dict[i]
print('The roman numeral %s entered is'%(roman_initial),Sum)
When you use the def keyword, you just define a function, but you don't run it.
what you're looking for is something more like this:
def generate_all_numerals(n):
...
def to_roman(n):
...
print "This program ..."
n = raw_input("Enter...")
print to_roman(n)
welcome to python :)