Convert an int to a Roman numeral

pip3 search roman-numerals
roman-numerals (0.1.0)               - A library to convert between integers
                                       and Unicode Roman numerals.

toroman.py

Please type an integer in the range 1 to 4999 inclusive: 2019
2019 = MMXIX

Please type an integer in the range 1 to 4999 inclusive: 1968
1968 = MCMLXVIII

Please type an integer in the range 1 to 4999 inclusive:

Things to try

  1. Change the four lists
    thousands = ["", "M", "MM", "MMM", "MMMM"]
    hundreds  = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]
    tens      = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]
    ones      = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]
    
    to the following list of four lists. See “nest lists” in Lists. Note that
    len(rows) is 4, because rows is a list containing 4 items.
    len(rows[0]) is 10, because rows[0] is a list of 10 items.
    len(rows[0][0]) is 0 because rows[0][0] is the string "" of 0 characters.
    rows = [
        ["", "M", "MM", "MMM", "MMMM"],
        ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"],
        ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"],
        ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]
    ]
    
    Change the definition of the toRoman function from
    def toRoman(n):
        "Convert one integer to a Roman numeral."
        assert isinstance(n, int) and 1 <= n <= 4999
    
        d = f"{n:04}"    #d is a string of 4 digits.
    
        i = int(d[0])    #d[0] is the leftmost digit.
        s = thousands[i]
    
        i = int(d[1])    #d[1] is the next-to-leftmost digit.
        s += hundreds[i] #means s = s + hundreds[i]
    
        i = int(d[2])    #d[2] is the third-from-leftmost digit.
        s += tens[i]
    
        i = int(d[3])    #d[3] is the fourth-from-leftmost digit.
        s += ones[i]
    
        return s
    
    to
    def toRoman(n):
        "Convert one integer to a Roman numeral."
        assert isinstance(n, int) and 1 <= n <= 4999
    
        d = f"{n:04}"    #d is a string of 4 digits.
    
        i = int(d[0])
        s = rows[0][i]
    
        i = int(d[1])
        s += rows[1][i]  #means s = s + rows[1][i]
    
        i = int(d[2])
        s += rows[2][i]
    
        i = int(d[3])
        s += rows[3][i]
    
        return s
    
    and then to
    def toRoman(n):
        "Convert one integer to a Roman numeral."
        assert isinstance(n, int) and 1 <= n <= 4999
    
        d = f"{n:04}"    #d is a string of 4 digits.
        s = ""
    
        for r, c in enumerate(d): #r is the row number: 0, 1, 2, 3
            i = int(c)
            s = s + rows[r][i]    #or s += rows[r][i]
    
        return s
    
    or even to the following. t is a tuple containing two items. The integer t[0] is what we just called r, and the one-character string t[1] is what we just called c.
    import functools
    
    def toRoman(n):
        "Convert one integer to a Roman numeral."
        assert isinstance(n, int) and 1 <= n <= 4999
    
        d = f"{n:04}"    #d is a string of 4 digits.
        return functools.reduce(lambda s, t: s + rows[t[0]][int(t[1])], enumerate(d), "")
    
  2. Convert a Roman numeral to an int.
    def fromRoman(s):
        "Convert a Roman numeral to an integer."
        assert isinstance(s, str)
    
        n = 0
        place = 1000
    
        for row in rows:
            prefixes = [prefix for prefix in row if s.startswith(prefix)]
            longestPrefix = max(prefixes, key = len)
            i = row.index(longestPrefix)
            n += place * i               #means n = n + place * i
            s = s[len(longestPrefix):]   #Chop longestPrefix off the front of s
            place //= 10                 #means place = place // 10
    
        if s != "":
            raise ValueError(f'"{s}" is not a Roman numeral.')
        return n