Basic program to convert integer to Roman numerals?

后端 未结 24 1116
孤独总比滥情好
孤独总比滥情好 2020-11-30 11:52

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_

相关标签:
24条回答
  • 2020-11-30 12:20

    start subtracting 1000,900... to 1 from A and stops when it finds positive.add corresponding roman to ans and make A to A-i where i is (1,4,5,9,10.....) repeat while A does not become 0.

    def intToRoman(self, A):
        l=[[1,'I'],[4,'IV'],[5,'V'],[9,'IX'],[10,'X'],[40,'XL'],[50,'L'],
           [90,'XC'],[100,'C'],[400,'CD'],[500,'D'],[900,'CM'],[1000,'M']]
        ans=""
        while(A>0):
            for i,j in l[::-1]:
                if A-i>=0:
                    ans+=j
                    A=A-i
                    break
        return ans
    
    0 讨论(0)
  • 2020-11-30 12:22

    Another way. I wrote recursive loop by roman symbols, so the max depth of recursion equals length of roman tuple:

    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 get_romans(number):
        return do_recursive(number, 0, '')
    
    
    def do_recursive(number, index, roman):
        while number >= ROMAN[index][0]:
            number -= ROMAN[index][0]
            roman += ROMAN[index][1]
        if number == 0:
            return roman
        return check_recursive(number, index + 1, roman)
    
    
    if __name__ == '__main__':
        print(get_romans(7))
        print(get_romans(78))
    
    0 讨论(0)
  • 2020-11-30 12:23
    def test(num):
    
        try:
            if type(num) != type(1):
                raise Exception("expected integer, got %s" % type(num))
            if not 0 < num < 4000:
                raise Exception("Argument must be between 1 and 3999")
            ints = (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1)
            nums = ('M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I')
            result = ""
            for i in range(len(ints)):
                count = int(num / ints[i])
                result += nums[i] * count
                num -= ints[i] * count
            print result
        except Exception as e:
            print e.message
    
    0 讨论(0)
  • 2020-11-30 12:24

    I have observed that in most of the answers, people are storing excess notations like "IX" for 9, "XL" for 40 and so on.

    This misses the main essence of Roman Conversion.

    Here's a small introduction and algorithm before I actually paste the code.

    The original pattern for Roman numerals used the symbols I, V. and X (1, 5, and 10) as simple tally marks. Each marker for 1 (I) added a unit value up to 5 (V), and was then added to (V) to make the numbers from 6 to 9:

    I, II, III, IIII, V, VI, VII, VIII, VIIII, X.

    The numerals for 4 (IIII) and 9 (VIIII) proved problematic, and are generally replaced with IV (one less than 5) and IX (one less than 10). This feature of Roman numerals is called subtractive notation.

    The numbers from 1 to 10 (including subtractive notation for 4 and 9) are expressed in Roman numerals as follows:

    I, II, III, IV, V, VI, VII, VIII, IX, X.

    The system being basically decimal, tens and hundreds follow the same pattern: Thus 10 to 100 (counting in tens, with X taking the place of I, L taking the place of V and C taking the place of X):

    X, XX, XXX, XL, L, LX, LXX, LXXX, XC, C. Roman Numerals - Wikipedia

    So, the main logic that can derive from the above introduction is that, we would strip the positional value and perform divisions based on the values of the literals Romans used.

    Let's start the base example. We have the integral list of the literals as [10, 5, 1]

    1. 1/10 = 0.1 (not of much use)

      1/5 = 0.2 (not of much use, either)

      1/1 = 1.0 (hmm, we got something!)

      CASE 1: So, if quotient == 1, print the literal corresponding to the integer. So, the best data structure would be a dictionary. {10: "X", 5: "V", 1:"I"}

      "I" will be printed.

    2. 2/10 = 0.2

      2/5 = 0.4

      2/1 = 2

      CASE 2: So, if quotient > 1, print the literal corresponding to the integer which made it so and subtract it from the number. This makes it 1 and it falls to CASE 1. "II" is printed.

    3. 3/10 = 0.3

      3/5 = 0.6

      3/1 = 3

      So, CASE 2: "I", CASE 2: "II" and CASE 1: "III"

    4. CASE 3: Add 1 and check if quotient == 1.

      (4+1)/10 = 0.5

      (4+1)/5 = 1

      So, this is the case where we first subtract the divisor and the number and print the literal corresponding to the result, followed by the divisor. 5-4=1, thus "IV" will be printed.

    5. (9+1)/10 == 1

      10-9=1. Print "I", print "X", i.e. "IX"

    This extends to the tenths place and hundredths as well.

    1. (90+(10^1))/100 = 1.

      Print 100-90="X", followed by 100="C".

    2. (400+(10^2))/500 = 1.

      Print 500-400="C", followed by 500="D".

    The last thing we need here is, extract the positional values. Ex: 449 should yield 400, 40, 9.

    This can be made by removing the subtracting the modulo of 10^(position-1) and then taking the modulo of 10^position.

    Ex: 449, position = 2: 449%(10^1) = 9 -> 449-9 -> 440%(10^2)= 40.

    '''
    Created on Nov 20, 2017
    
    @author: lu5er
    '''
    n = int(input())
    ls = [1000, 500, 100, 50, 10, 5, 1]
    st = {1000:"M", 500:"D", 100:"C", 50:"L", 10:"X", 5:"V", 1:"I"}
    
    rem = 0
    
    # We traverse the number from right to left, extracting the position
    for i in range(len(str(n)), 0, -1):
        pos = i # stores the current position
        num = (n-n%(10**(pos-1)))%(10**pos) # extracts the positional values
        while(num>0):
            for div in ls:
    
                # CASE 1: Logic for 1, 5 and 10
                if num/div == 1:
                    #print("here")
                    print(st[div], end="")
                    num-=div
                    break
    
                # CASE 2: logic for 2, 3, 6 and 8
                if num/div > 1:
                    print(st[div],end="")
                    num-=div
                    break
    
                # CASE 3: Logic for 4 and 9
                if (num+(10**(pos-1)))/div == 1:
                    print(st[div-num], end="")
                    print(st[div], end="")
                    num-=div
                    break
    

    Output Test

    99
    XCIX
    
    499
    CDXCIX
    
    1954
    MCMLIV
    
    1990
    MCMXC
    
    2014
    MMXIV
    
    35
    XXXV
    
    994
    CMXCIV
    
    0 讨论(0)
  • 2020-11-30 12:25

    One of the best ways to deal with this is using the divmod function. You check if the given number matches any Roman numeral from the highest to the lowest. At every match, you should return the respective character.

    Some numbers will have remainders when you use the modulo function, so you also apply the same logic to the remainder. Obviously, I'm hinting at recursion.

    See my answer below. I use an OrderedDict to make sure that I can iterate "downwards" the list, then I use a recursion of divmod to generate matches. Finally, I join all generated answers to produce a 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)])
    

    Taking it for a spin:

    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
    
    0 讨论(0)
  • 2020-11-30 12:26

    Here is my approach to solving this. The given number is first converted to a string so that then we can easily iterate over every digit to get the Roman part for the corresponding digit. To get the roman part for each digit I have grouped the Roman letters into 1 and 5 for each decimal position so the list of roman characters grouped based on decimal positions would look like [['I', 'V'], ['X', 'L'], ['C', 'D'], ['M']], where characters follow the order or ones, tens, hundreds, and thousands.

    So we have digits to loop over and the roman characters for each order of the decimal place, we just need to prepare digits 0-9 using the above character list. The variable "order" picks the correct set of characters based on the decimal position of current digit, this is handled automatically as we are going from highest decimal place to lowest. Following is the full code:

    def getRomanNumeral(num):
        # ---------- inner function -------------------
        def makeRomanDigit(digit, order):    
            chars = [['I', 'V'], ['X', 'L'], ['C', 'D'], ['M']]
            if(digit == 1):
                return chars[order][0]
            if(digit == 2):
                return chars[order][0] + chars[order][0]
            if(digit == 3):
                return chars[order][0] + chars[order][0] + chars[order][0]
            if(digit == 4):
                return  chars[order][0] + chars[order][1]
            if(digit == 5):
                return chars[order][1]
            if(digit == 6):
                return chars[order][1] + chars[order][0]
            if(digit == 7):
                return chars[order][1] + chars[order][0] + chars[order][0]
            if(digit == 8):
                return chars[order][1] + chars[order][0] + chars[order][0] + chars[order][0]
            if(digit == 9):
                return chars[order][0] + chars[order+1][0]
            if(digit == 0):
                return ''
        #--------------- main -----------------
        str_num = str(num)
        order = len(str_num) - 1
        result = ''
        for digit in str_num:
            result += makeRomanDigit(int(digit), order)
            order-=1
        return result
    

    A few tests:

    getRomanNumeral(112)
    'CXII'
    
    getRomanNumeral(345)
    'CCCXLV'
    
    getRomanNumeral(591)
    'DXCI'
    
    getRomanNumeral(1000)
    'M'
    

    I know a lot can be improved in the code or approach towards the problem, but this was my first attempt at this problem.

    0 讨论(0)
提交回复
热议问题