Basic program to convert integer to Roman numerals?

后端 未结 24 1114
孤独总比滥情好
孤独总比滥情好 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:11

    The approach by Laughing Man works. Using an ordered dictionary is clever. But his code re-creates the ordered dictionary every time the function is called, and within the function, in every recursive call, the function steps through the whole ordered dictionary from the top. Also, divmod returns both the quotient and the remainder, but the remainder is not used. A more direct approach is as follows.

    def _getRomanDictOrdered():
        #
        from collections import OrderedDict
        #
        dIntRoman = OrderedDict()
        #
        dIntRoman[1000] = "M"
        dIntRoman[900] = "CM"
        dIntRoman[500] = "D"
        dIntRoman[400] = "CD"
        dIntRoman[100] = "C"
        dIntRoman[90] = "XC"
        dIntRoman[50] = "L"
        dIntRoman[40] = "XL"
        dIntRoman[10] = "X"
        dIntRoman[9] = "IX"
        dIntRoman[5] = "V"
        dIntRoman[4] = "IV"
        dIntRoman[1] = "I"
        #
        return dIntRoman
    
    _dIntRomanOrder = _getRomanDictOrdered() # called once on import
    
    def getRomanNumeralOffInt( iNum ):
        #
        lRomanNumerals = []
        #
        for iKey in _dIntRomanOrder:
            #
            if iKey > iNum: continue
            #
            iQuotient = iNum // iKey
            #
            if not iQuotient: continue
            #
            lRomanNumerals.append( _dIntRomanOrder[ iKey ] * iQuotient )
            #
            iNum -= ( iKey * iQuotient )
            #
            if not iNum: break
            #
        #
        return ''.join( lRomanNumerals )
    

    Checking the results:

    >>> getRomanNumeralOffInt(35)
    'XXXV'
    >>> getRomanNumeralOffInt(994)
    'CMXCIV'
    >>> getRomanNumeralOffInt(1995)
    'MCMXCV'
    >>> getRomanNumeralOffInt(2015)
    'MMXV'
    
    0 讨论(0)
  • 2020-11-30 12:11

    Write a simple code which takes the number, decreases the number, and appends its corresponding value in Roman numerals in a list and finally converts it in the string. This should work for range 1 to 3999

    for no in range(1,3999):
        r_st=list()
        a=no
        while(no>1000):
            r_st.append("M")
            no-=1000
        if(no>899 and no<1000):
            r_st.append("CM")
            no-=900
        if(no>499):
            r_st.append("D")
            no-=500
        if(no>399):
            r_st.append("CD")
            no-=400
        while(no>99):
            r_st.append("C")
            no-=100
        if(no>89):
            r_st.append("LC")
            no-=90
        if(no>50):
            r_st.append("L")
            no-=50
        if(no>39):
            r_st.append("XL")
            no-=40
        while(no>9):
            r_st.append("X")
            no-=10
        if(no>8):
            r_st.append("IX")
            no-=9
        if(no>4):
            r_st.append("V")
            no-=5
        if(no>3):
            r_st.append("IV")
            no-=4
        while(no>0):
            r_st.append("I")
            no-=1
        r_st=''.join(r_st)
        print(a,"==",r_st)
    
    0 讨论(0)
  • 2020-11-30 12:12

    You have to make the symbolCount a global variable. And use () in print method.

    0 讨论(0)
  • 2020-11-30 12:12

    Another way to do this. separating out processing of number starting with 4 , 9 and others. it can be simplified further

    def checkio(data):
    romans = [("I",1),("V",5),("X",10),("L",50),("C",100),("D",500),("M",1000)]
    romans_rev = list(sorted(romans,key = lambda x: -x[1]))
    def process_9(num,roman_str):
        for (k,v) in romans:
            if (v > num):
                current_roman = romans[romans.index((k,v))]
                prev_roman = romans[romans.index((k,v)) - 2]
                roman_str += (prev_roman[0] + current_roman[0])
                num -= (current_roman[1] - prev_roman[1])
                break
        return num,roman_str
    def process_4(num,roman_str):
        for (k,v) in romans:
            if (v > num):
                current_roman = romans[romans.index((k,v))]
                prev_roman = romans[romans.index((k,v)) - 1]
                roman_str += (prev_roman[0] + current_roman[0])
                num -= (current_roman[1] - prev_roman[1])
                break
        return num,roman_str
    def process_other(num,roman_str):
        for (k,v) in romans_rev:
            div = num // v
            if ( div != 0 and num > 0 ):
                roman_str += k * div
                num -= v * div
                break
        return num,roman_str
    def get_roman(num):
        final_roman_str = ""
        while (num > 0):
            if (str(num).startswith('4')):
                num,final_roman_str = process_4(num,final_roman_str)
            elif(str(num).startswith('9')):
                num,final_roman_str = process_9(num,final_roman_str)
            else:
                num,final_roman_str = process_other(num,final_roman_str)
        return final_roman_str
    
    return get_roman(data)
    
    
    print(checkio(number))
    
    0 讨论(0)
  • 2020-11-30 12:15

    Here's a lambda function for integer to roman numeral conversion, working up to 3999. It anchors some corner of the space of "unreadable things you probably don't actually want to do". But it may amuse someone:

    lambda a: (
        "".join(reversed([
          "".join([
              "IVXLCDM"[int(d)+i*2]
              for d in [
                  "", "0", "00", "000", "01",
                  "1", "10", "100", "1000", "02"][int(c)]])
              for i,c in enumerate(reversed(str(a))) ]))
         )
    

    This approach gives an alternative to using arithmetical manipulations to isolate decimal digits and their place, as OP and many of the examples do. The approach here goes straight for converting the decimal number to a string. That way, digits can be isolated by list indexing. The data table is fairly compressed, and no subtraction or division is used.

    Admittedly, in the form given, whatever is gained in brevity is immediately given up in readability. For people without time for puzzles, a version below is given that avoids list comprehension and lambda functions.

    Stepthrough

    But I'll explain the lambda function version here...

    Going from back to front:

    1. Convert a decimal integer to a reversed string of its digits, and enumerate (i) over the reversed digits (c).

      ....
      for i,c in enumerate(reversed(str(a)))
      ....
      
    2. Convert each digit c back to an integer (range of 0-9), and use it as an index into a list of magic digit strings. The magic is explained a little later on.

      ....
      [ "", "0", "00", "000", "01",
       "1", "10", "100", "1000", "02"][int(c)]])
      ....
      
    3. Convert your selected magic digit string into a string of roman numeral "digits". Basically, you now have your decimal digit expressed as roman numeral digits appropriate to the original 10's place of the decimal digit. This is the target of the generate_all_of_numeral function used by the OP.

      ....
      "".join([
          "IVXLCDM"[int(d)+i*2]
          for d in <magic digit string>
      ....
      
    4. Concatenate everything back in reversed order. The reversal is of the order of the digits, but order within the digits ("digits"?) is unaffected.

      lambda a: (
          "".join(reversed([
          <roman-numeral converted digits>
          ]))
      

    The Magic String List

    Now, about that list of magic strings. It allows selecting the appropriate string of roman numeral digits (up to four of them, each being one of three types 0, 1, or 2) for each different 10's place that a decimal digit can occupy.

    • 0 -> ""; roman numerals don't show zeros.
    • 1 -> "0"; 0 + 2*i maps to I, X, C or M -> I, X, C or M.
    • 2 -> "00"; like for 1, x2 -> II, XX, CC, MM.
    • 3 -> "000"; like for 1, x3 -> III, XXX, CCC, MMM.
    • 4 -> "01"; like for 1, then 1 +2*i maps to V, L, or D -> IV, XL, CD.
    • 5 -> "1"; maps to odd roman numeral digits -> V, L, D.
    • 6 -> "10"; reverse of 4 -> VI, LX, DC.
    • 7 -> "100"; add another I/X/C -> VII LXX, DCC
    • 8 -> "1000"; add another I/X/C -> VIII, LXXX, DCCC
    • 9 -> "02"; like for 1, plus the next 10's level up (2 + i*2) -> IX, XC, CM.

    At 4000 and above, this will throw an exception. "MMMM" = 4000, but this doesn't match the pattern anymore, breaking the assumptions of the algorithm.

    Rewritten version

    ...as promised above...

    def int_to_roman(a):
        all_roman_digits = []
        digit_lookup_table = [
            "", "0", "00", "000", "01",
            "1", "10", "100", "1000", "02"]
        for i,c in enumerate(reversed(str(a))):
            roman_digit = ""
            for d in digit_lookup_table[int(c)]:
              roman_digit += ("IVXLCDM"[int(d)+i*2])
            all_roman_digits.append(roman_digit)
        return "".join(reversed(all_roman_digits))
    

    I again left out exception trapping, but at least now there's a place to put it inline.

    0 讨论(0)
  • 2020-11-30 12:17

    I referred to this url for online decimal to roman conversion. If we extend the range of decimals up to 3,999,999 the script given by @Manhattan will not work. Here is the the correct script up to the range of 3,999,999.

    def int_to_roman(num):
        _values = [
            1000000, 900000, 500000, 400000, 100000, 90000, 50000, 40000, 10000, 9000, 5000, 4000, 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
    
        _strings = [
            'M', 'C', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
    
        result = ""
        decimal = num
    
        while decimal > 0:
            for i in range(len(_values)):
                if decimal >= _values[i]:
                    if _values[i] > 1000:
                        result += u'\u0304'.join(list(_strings[i])) + u'\u0304'
                    else:
                        result += _strings[i]
                    decimal -= _values[i]
                    break
        return result
    

    The unicode character u'\0304' prints the overline char; e.g.

    Sample Output:

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