RosettaCodeData/Task/Roman-numerals-Encode/Python/roman-numerals-encode-6.py

65 lines
1.6 KiB
Python

'''Encoding Roman Numerals'''
from functools import reduce
from itertools import chain
# romanFromInt :: Int -> String
def romanFromInt(n):
'''A string of Roman numerals encoding an integer.'''
def go(a, ms):
m, s = ms
q, r = divmod(a, m)
return (r, s * q)
return concat(snd(mapAccumL(go)(n)(
zip([1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX',
'V', 'IV', 'I'])
)))
# MAIN -------------------------------------------------
# main :: IO ()
def main():
'''Test'''
print(
list(map(romanFromInt, [1666, 1990, 2008, 2016, 2018]))
)
# GENERIC FUNCTIONS ---------------------------------------
# concat :: [[a]] -> [a]
# concat :: [String] -> String
def concat(xxs):
'''The concatenation of all the elements in a list.'''
xs = list(chain.from_iterable(xxs))
unit = '' if isinstance(xs, str) else []
return unit if not xs else (
''.join(xs) if isinstance(xs[0], str) else xs
)
# mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
def mapAccumL(f):
'''A tuple of an accumulation and a list derived by a
combined map and fold,
with accumulation from left to right.'''
def go(a, x):
tpl = f(a[0], x)
return (tpl[0], a[1] + [tpl[1]])
return lambda acc: lambda xs: (
reduce(go, xs, (acc, []))
)
# snd :: (a, b) -> b
def snd(tpl):
'''Second component of a tuple.'''
return tpl[1]
# MAIN ---
if __name__ == '__main__':
main()