Esta es la respuesta más correcta que te podemos compartir, pero primero mírala detenidamente y analiza si se adapta a tu proyecto.
Solución:
Una de las mejores maneras de lidiar con esto es usando el divmod
función. Verifica si el número dado coincide con cualquier número romano desde el más alto hasta el más bajo. En cada partido, debe devolver el carácter respectivo.
Algunos números tendrán residuos cuando utilice la función de módulo, por lo que también aplica la misma lógica al resto. Obviamente, estoy insinuando recursividad.
Vea mi respuesta a continuación. yo uso un OrderedDict
para asegurarme de que puedo iterar “hacia abajo” la lista, luego uso una recursión de divmod
para generar coincidencias. Finalmente yo join
todas las respuestas generadas para producir una string.
from collections import OrderedDict
def write_roman(num):
roman = OrderedDict()
roman[1000] = "M"
roman[900] = "CM"
roman[500] = "D"
roman[400] = "CD"
roman[100] = "C"
roman[90] = "XC"
roman[50] = "L"
roman[40] = "XL"
roman[10] = "X"
roman[9] = "IX"
roman[5] = "V"
roman[4] = "IV"
roman[1] = "I"
def roman_num(num):
for r in roman.keys():
x, y = divmod(num, r)
yield roman[r] * x
num -= (r * x)
if num <= 0:
break
return "".join([a for a in roman_num(num)])
Dando una vuelta:
num = 35
print write_roman(num)
# XXXV
num = 994
print write_roman(num)
# CMXCIV
num = 1995
print write_roman(num)
# MCMXCV
num = 2015
print write_roman(num)
# MMXV
Aquí hay otra manera, sin división:
num_map = [(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 num2roman(num):
roman = ''
while num > 0:
for i, r in num_map:
while num >= i:
roman += r
num -= i
return roman
# test
>>> num2roman(2242)
'MMCCXLII'
Actualizar ver la ejecución visualizada
Una versión KISS del algoritmo de Manhattan, sin ninguna noción "avanzada" como OrderedDict
recursión, generadores, función interna y 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
Una salida prematura podría agregarse tan pronto como number
llega a cero y el string la acumulación podría hacerse más pitónica, pero mi objetivo aquí era producir el pedido básico programa.
Probado en todos los números enteros del 1 al 100000, lo que debería ser suficiente para cualquiera.
EDITAR: la versión un poco más pitónica y más rápida a la que aludí:
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)