-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathroman_numerals.py
More file actions
55 lines (44 loc) · 1.38 KB
/
roman_numerals.py
File metadata and controls
55 lines (44 loc) · 1.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
"""
Convert between Roman numeral and int. A few variants.
"""
def int_from_roman1(string):
def convert((i, c)):
return -values[c] if string[i:i+2] in almost else values[c]
return sum(map(convert, enumerate(string)))
values = {'M': 1000, 'D': 500, 'C': 100, 'L': 50, 'X': 10, 'V': 5, 'I': 1}
almost = 'CM CD XC XL IX IV'.split()
# After a more elegant answer in Java: http://stackoverflow.com/a/25411754/27024
def int_from_roman2(string):
acc = prev = 0
for c in reversed(string):
v = values[c]
if prev <= v: acc += v
else: acc -= v
prev = v
return acc
# After Dave Long's version of the above.
def int_from_roman3(string):
v = [values[c] for c in string]
return sum(digit * positively(peek <= digit)
for digit, peek in zip(v, v[1:]+[0]))
def positively(flag):
return 1 if flag else -1
## int_from_roman1('MCMLXXIX')
#. 1979
## int_from_roman2('MCMLXXIX')
#. 1979
## int_from_roman3('MCMLXXIX')
#. 1979
"""
And the inverse. Disappointing to use different tables.
"""
def roman_from_int(n):
tens, ones = divmod(n, 10)
return (times_X(roman_from_int(tens)) if tens else '') + digits[ones]
def times_X(numeral):
return ''.join(places[c] for c in numeral)
digits = ' I II III IV V VI VII VIII IX'.split(' ')
places = dict(zip('IVXLC',
'XLCDM'))
## roman_from_int(1979)
#. 'MCMLXXIX'