Converting Roman Numerals to integers in python

前端 未结 17 1585
挽巷
挽巷 2020-12-03 03:56

This is now my current code after what user2486 said.

def romanMap():
    map=((\"M\",  1000),(\"CM\", 900),(\"D\",  500),(\"CD\", 400),(\"C\",  100),(\"XC\"         


        
相关标签:
17条回答
  • 2020-12-03 04:06

    Right-to-left solution that is a bit more Pythonic (no indexes) and relatively short.

    Algorithm:

    • Reverse the roman numeral and map it to a list of numbers
    • Figure out which numbers should be subtracted and then sum the list

    Example:

    'xiv' => sum(5, -1, 10) => 14

    def parse_roman(s):
        numerals = {'M':1000, 'D':500, 'C':100, 'L':50, 'X':10, 'V':5, 'I':1}
        n = 0
        last_value = 0
        # e.g. convert 'xiv' to (5, 1, 10)
        for value in (numerals[c] for c in reversed(s.upper())):
            # debugging
            v = (value, -value)[value < last_value]
            print('{:6} += {:5}  <== cur, prev = {}, {}'.format(n, v, value, last_value))
            # subtract smaller values that come after larger ones, otherwise add
            n += (value, -value)[value < last_value]
            last_value = value
        return n
    

    Output:

    parse_roman('MMCMXCVIII')
         0 +=     1  <== cur, prev = 1, 0
         1 +=     1  <== cur, prev = 1, 1
         2 +=     1  <== cur, prev = 1, 1
         3 +=     5  <== cur, prev = 5, 1
         8 +=   100  <== cur, prev = 100, 5
       108 +=   -10  <== cur, prev = 10, 100
        98 +=  1000  <== cur, prev = 1000, 10
      1098 +=  -100  <== cur, prev = 100, 1000
       998 +=  1000  <== cur, prev = 1000, 100
      1998 +=  1000  <== cur, prev = 1000, 1000
    2998
    

    Note: It would be nice to find a (short, inline) method for changing the signs of the sequence on the fly. For example, (5, 1, 10) ==> (5, -1, 10).


    Update: This is as close as I got before giving up. It's identical to the code above, but it uses itertools.tee() with zip() to generate pairs of the previous and current values to eliminate the need for the state variables. The single call to next(cur) makes that list one shorter than prev which is all the state we need to figure out whether to add or subtract the current value.

    Example:

    cur, prev = (5, 1, 10), (5, 1, 10)
    # Take one from cur and zip the rest
    next(cur) + sum(... zip(cur, prev))
    # 5 + ... zip( (1, 10), (5, 1, 10) )  ==>  5 + ... ((1, 5), (10, 1)) 
    

    Code:

    from itertools import tee
    
    def parse_roman(s):
        numerals = {'M':1000, 'D':500, 'C':100, 'L':50, 'X':10, 'V':5, 'I':1}
        cur, prev = tee(numerals[c] for c in reversed(s.upper()))
        return next(cur) + sum((cur, -cur)[cur < prev] for cur, prev in zip(cur,prev))
    
    0 讨论(0)
  • 2020-12-03 04:06
    roman_conver=[  (1,'I'),
                    (5,'V'),
                    (10,'X'),
                    (50,'L'),
                    (100,'C'),
                    (500,'D'),
                    (1000,'M'),
                        ]
    def romantonumeral(roman):
        tot = 0
        for i in range(0,len(roman)):
            for each in roman_conver:
                if roman[i]==each[1]:
                    if each[0]>tot:
                        tot = each[0] - tot
                    else:
                        tot = tot + each[0]
        return tot
    
    0 讨论(0)
  • 2020-12-03 04:08

    Consider this additional pseudo-code and hints (some of it is valid Python, some isn't, but there be notes).

    def numberOfNumeral(n):
        """ Return the number represented by the single numeral """
        # e.g. "v" -> 5, "i" -> 5 (and handle v/V cases, etc.)
    
    # avoid "string" as a variable name
    # I chose "ns" for "numerals" (which might be better),
    # but I'm also a bit terse .. anyway, name variables for what they represents.
    ns = str(input("Enter a roman numeral"))
    
    while ns:
       firstNum = numberOfNumeral(ns[0])
       # This makes secondValue = -1 when there is only one numeral left
       # so firstNum is always "at least" secondNum when len(ns) == 1. 
       secondNum = numberOfNumeral(ns[1]) if len(ns) > 1 else -1
       if firstNum is at least secondNum:
          # Add firstNum to total.
          # Remove the character - so that the loop state advances.
          # If we don't don't his, as in the original, it will never end.
          # Here we use "slice notation".
          ns = ns[1:] 
       else:
          # Add the difference, secondNum - firstNum, to total.
          # Remove both characters - again, so we advance state.
          ns = ns[2:]
    
    • Explain Python's slice notation
    • Does Python have a ternary conditional operator?
    0 讨论(0)
  • 2020-12-03 04:10

    You can use this code:

    def roman_integer(roman):
        roman = roman.upper() # for taking care of upper or lower case letters
        integer_rep = 0
        roman_to_integer_map = tuple()
        roman_to_integer_map = (('M',1000),
                                ('CM',900),
                                ('D',500),
                                ('CD',400),
                                ('C',100),
                                ('XC',90),
                                ('L',50),
                                ('XL',40),
                                ('X',10),
                                ('IX',9),
                                ('V',5),
                                ('IV',4),
                                ('I',1))
        roman_numeral_pattern = re.compile("""
        ^                   # beginning of string
        M{0,4}              # thousands - 0 to 4 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                   # end of string
        """ ,re.VERBOSE)
    
        if not roman_numeral_pattern.search(roman):
            return 0
        index = 0
        for numeral, integer in roman_to_integer_map:
            while roman[index:index+len(numeral)] == numeral:
                #print numeral, integer, 'matched'
                integer_rep += integer
                index += len(numeral)
        return integer_rep

    0 讨论(0)
  • 2020-12-03 04:13

    This is one of the leetcode questions.

    def romanToInt(s):
        sum=0
        dict={'M':1000,'D':500,'C':100,'L':50,'X':10,'V':5,'I':1}
    
        for i in range(len(s)):
            if i==0:
                sum=sum+dict[s[i]]
            else:
                if s[i]=='M':
                    sum=sum+1000
                    if s[i-1]=='C':
                        sum=sum-200      
    
                elif s[i]=='D':
                    sum=sum+500
                    if s[i-1]=='C':
                        sum=sum-200
    
                elif s[i]=='C':
                    sum=sum+100
                    if s[i-1]=='X':
                        sum=sum-20
    
                elif s[i]=='L':
                    sum=sum+50
                    if s[i-1]=='X':
                        sum=sum-20
    
                elif s[i]=='X':
                    sum=sum+10
                    if s[i-1]=='I':
                        sum=sum-2
    
                elif s[i]=='V':
                    sum=sum+5
                    if s[i-1]=='I':
                        sum=sum-2
                elif s[i]=='I':
                    sum=sum+1
        return (sum)
    
    0 讨论(0)
  • 2020-12-03 04:15

    Here's something i came up with using dictionary. It should be v.simple. Tell me what you think. I must say it does not handle the spoof roman numerals written in the form of MIM (instead of MCMXCIX for 1999). This is only for valid roman numerals.

    import re
    s = 0;
    a = dict();
    b = dict();
    r = "MMCMXCVIII"
    
    a['CM'] = 900;
    a['IX'] = 9;
    a ['IV'] = 4;
    a ['XL'] = 40;
    a ['CD'] = 400;
    a ['XC'] = 90;
    
    b['M'] = 1000;
    b['C'] = 100;
    b['D'] = 500;
    b['X'] = 10;
    b['V'] = 5;
    b['L'] = 50;
    b['I'] = 1;
    
    # Handle the tricky 4's and 9's first and remove them from the string
    
    for key in a:
            if key in r: 
                r = re.sub(key,'',r)
                s+=a[key];
    # Then straightforward multiplication of the not-so-tricky ones by their count.
    
    for key in b:
             s+= r.count(key) * b[key];
    
    print s; # This will print 2998
    
    0 讨论(0)
提交回复
热议问题