Search code examples
python-3.xstringlistsortingroman-numerals

Sort Royal King names with python


Hi I'm trying to solve this problem but I can't solve these errors
The idea of how I wanted to solve the problem is by first splitting the names into names and Roman number and after that converting Roman to Arabic numbers, after that sort like integers and do the conversion in reverse Arabic to Roman

def from_roman(num):
    roman_numerals = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
    result = 0
    for i,c in enumerate(num):
        if (i+1) == len(num) or roman_numerals[c] >= roman_numerals[num[i+1]]:
            result += roman_numerals[c]
        else:
            result -= roman_numerals[c]
    return result

# convert from arabic to roman
def to_roman(num):
    roman_numerals = {1:'I', 5:'V', 10:'X', 50:'L', 100:'C', 500:'D', 1000:'M'}
    result=''
    for i,c in enumerate(num):
        if (i+1) == len(num) or roman_numerals[c] >= roman_numerals[num[i+1]]:
            result += roman_numerals[c]
        else:
            result -= roman_numerals[c]
    return result

def SortPrintKingsNames(kings):
    
    romanList=[]
    arabicList=[]
    #sort kings name first
    kings.sort()
    #sort roman numbers by converting them to arabic and sorting them
    for king in kings:
        romanList.append(from_roman(king.split()[-1]))
    romanList.sort()
    #convert to roman again      
    for roman in romanList:
        arabicList=to_roman(roman)
    
    for k in kings:
        # print names with roman number 
        print(k,arabicList[k])

Here are the errors:

Traceback (most recent call last):
  File "Solution.py", line 58, in <module>
    SortPrintKingsNames(kingsNames)
  File "Solution.py", line 48, in SortPrintKingsNames
    arabicList=to_roman(roman)
  File "Solution.py", line 29, in to_roman
    for i,c in enumerate(num):
TypeError: 'int' object is not iterable

Solution

  • The error is raised because you are trying to enumerate the arabic (integer) values.

    Update the to_roman function to resolve the issue.

    Try this code:

    def from_roman(num):  # IV > 4
        roman_numerals = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
        result = 0
        for i,c in enumerate(num):
            if (i+1) == len(num) or roman_numerals[c] >= roman_numerals[num[i+1]]:
                result += roman_numerals[c]
            else:
                result -= roman_numerals[c]
        return result
    
    # convert from arabic to roman
    def to_roman(num):   #  4 > IV
        roman_numerals = {1:'I', 5:'V', 10:'X', 50:'L', 100:'C', 500:'D', 1000:'M'}
        result=''
        for k in list(roman_numerals.keys())[::-1]:
           while num >= k:
              result+=roman_numerals[k]
              num -= k
        # do replacements based on 'max 3' rule
        rt = [('DCCCC','CM'), ('CCCC','CD'), ('LXXXX','XC'), ('XXXX','XL'), ('VIIII','IX'), ('IIII','IV')]
        for r in rt:
            result = result.replace(*r) # convert tuple to args
    #    for i,c in enumerate(num):
    #        if (i+1) == len(num) or roman_numerals[c] >= roman_numerals[num[i+1]]:
    #            result += roman_numerals[c]
    #        else:
    #            result -= roman_numerals[c]
        return result
    
    def SortPrintKingsNames(kings):
        print(kings)
        romanList=[]
        arabicList=[]
        #sort kings name first
        #kings.sort()
        #sort roman numbers by converting them to arabic and sorting them
        #romanlist = from_roman(kings)
        for king in kings:
            romanList.append(from_roman(king.split()[-1]))
        print(romanList)
        romanList.sort()
        print(romanList)
        #convert to roman again      
        for roman in romanList:
            arabicList.append(to_roman(roman))
        
        print(arabicList)
    #    for k in kings:
            # print names with roman number 
    #        print(k,arabicList[k])
    
    k = SortPrintKingsNames(['VI','I','IC','XX'])
    

    Output

    ['VI', 'I', 'IC', 'XX']
    [6, 1, 99, 20]
    [1, 6, 20, 99]
    ['I', 'VI', 'XX', 'XCIX']
    

    Note that IC (99) is not a valid roman numeral, so it is converted to XCIX.

    Replacements are done based on the 'max 3' rule. Only 6 replacements are needed for any number so it's cleaner to list the replacements instead of using a complicated loop.

    Roman numeral rules (note rule #4):

    https://classace.io/learn/math/3rdgrade/roman-numerals-ivxlcdm

    As a side note, if this is being used for regnal numbers, the biggest number you need is 72 (LXXII).

    https://en.wikipedia.org/wiki/Heinrich_LXXII,_Prince_Reuss_of_Lobenstein_and_Ebersdorf