erlang 将数字转换为等效的罗马数字

iyfamqjs  于 2022-12-08  发布在  Erlang
关注(0)|答案(4)|浏览(293)

我已经尝试了数字转换成它的等效罗马数字。请建议我减少实现的代码获得输出。也请建议在Erlang相同的场景(在标签中提到),这将更有助于理解Erlang。
尝试的代码:

***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 sub(Num,Num2):
      Num1 = Num - Num2
      N = Num - Num1
      return N
    def roman_convert(Num,roman) :
      #print(roman)
      while( Num > 0):
        if Num >= 1000:
           N = sub(Num,1000)
           roman.append(Roman.get(N))
           Num = Num - 1000
        elif Num >= 900:
           N = sub(Num,900)
           roman.append(Roman.get(N))
           Num = Num - 900
        elif Num >= 500:
            N = sub(Num,500)
            roman.append(Roman.get(N))
            Num = Num - 500
        elif Num >= 400:
           N = sub(Num,400)
           roman.append(Roman.get(N))
           Num = Num - 400
        elif Num >= 100:
           N = sub(Num,100)
           roman.append(Roman.get(N))
           Num = Num - 100
        elif Num >= 90:
           N = sub(Num,90)
           roman.append(Roman.get(N))
           Num = Num - 90
        elif Num >= 50:
           N = sub(Num,50)
           roman.append(Roman.get(N))
           Num = Num - 50 
        elif Num >= 40:
           N = sub(Num,40)
           roman.append(Roman.get(N))
           Num = Num - 40   
        elif Num >= 10:
           N = sub(Num,10)
           roman.append(Roman.get(N))
           Num = Num - 10        
        elif Num >= 9:
           N = sub(Num,9)
           roman.append(Roman.get(N))
           Num = Num - 9
        elif Num >= 4:
           N = sub(Num,4)
           roman.append(Roman.get(N))
           Num = Num - 4
        elif Num >= 1:
           N = sub(Num,1)
           roman.append(Roman.get(N))
           Num = Num - 1
        else :
           roman.append(0) 
      return roman
    if __name__ == "__main__":
      print("Converting the Numbers into Roman:")
      Num = int(input("Enter the number :"))
      roman =[]
      R = roman_convert(Num,roman)
      Roman = "".join(str(x) for x in R)
      print(Roman)***

请建议我怎样即兴编密码?
以上代码的输出如下

**Converting the Numbers into Roman:
Enter the number :199
CXCIX**
lokaqttq

lokaqttq1#

这是一个非常严格的问题,但我个人遵循的一个解决方案也很简单。上面提到的here的答案与我遵循的答案相似,但下面的答案更短。但我相信逻辑是相同的。

def printRoman(number):
    num = [1, 4, 5, 9, 10, 40, 50, 90, 
           100, 400, 500, 900, 1000]
    sym = ["I", "IV", "V", "IX", "X", "XL", 
           "L", "XC", "C", "CD", "D", "CM", "M"]
    i = 12
    while number:
        div = number // num[i]
        number %= num[i]
 
        while div:
            print(sym[i], end = "")
            div -= 1
        i -= 1

n = int(input('Enter a number: '))
printRoman(n)

我已经从here了解到了这一点,你也可以参考那里的详细解释,这是如何工作的。

pqwbnv8z

pqwbnv8z2#

以下是Erlang的解决方案,并附有一些注解:
1.最多只能处理整数3999。如果需要更多,可以展开代码并相应地添加Map值。
1.测试场景基于this link中标题为 * 罗马数字转换表 * 的表。
测试结果:
编码:

-module(roman). 

-export([convert_to_roman/1]).
-export([test_convert_roman/1]).

-define(BASIC_ROMAN_NUMERAL_MAP, #{
                               0 => "",
                               1 => "I",
                               2 => "II",
                               3 => "III",
                               4 => "IV",
                               5 => "V",
                               6 => "VI",
                               7 => "VII",
                               8 => "VIII",
                               9 => "IX",
                               10 => "X",
                               20 => "XX",
                               30 => "XXX",
                               40 => "XL",
                               50 => "L",
                               60 => "LX",
                               70 => "LXX",
                               80 => "LXXX",
                               90 => "XC",
                               100 => "C",
                               200 => "CC",
                               300 => "CCC",
                               400 => "CD",
                               500 => "D",
                               600 => "DC",
                               700 => "DCC",
                               800 => "DCCC",
                               900 => "CM",
                               1000 => "M",
                               2000 => "MM",
                               3000 => "MMM"
                                }). 

convert_to_roman(Int) when Int > 0, Int < 4000 ->
    ThousandDiv = Int div 1000,
    Thousands = ThousandDiv * 1000,
    case ThousandDiv of
        0 -> ThousandsStr = "";
        _ -> ThousandsStr = maps:get(Thousands, ?BASIC_ROMAN_NUMERAL_MAP, "Unmapped1000")
    end,

    ThousandRem = Int - Thousands, 
    HundredDiv = ThousandRem div 100,
    Hundreds = HundredDiv * 100,
    case HundredDiv of
        0 -> HundredsStr = "";
        _ -> HundredsStr = maps:get(Hundreds, ?BASIC_ROMAN_NUMERAL_MAP, "Unmapped100")
    end,

    HundredRem = Int - Thousands - Hundreds,
    TensDiv = HundredRem div 10,
    Tens = TensDiv * 10,
    case TensDiv of
        0 -> TensStr = "";
        _ -> TensStr = maps:get(Tens, ?BASIC_ROMAN_NUMERAL_MAP, "Unmapped10")
    end,

    TensRem = Int - Thousands - Hundreds - Tens,
    OnesStr =  maps:get(TensRem, ?BASIC_ROMAN_NUMERAL_MAP, "Unmapped1"),
    ThousandsStr ++ HundredsStr ++ TensStr ++ OnesStr.
    
test_convert_roman(List) ->
    lists:foreach(fun(Int) -> 
                    Roman = convert_to_roman(Int), 
                    io:format("~p -> ~p~n", [Int, Roman])
                  end, 
                  List).

测试方法:

roman:test_convert_roman([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
                      21, 22, 23, 24, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100,
                      105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 175, 200, 225, 250, 275, 300,
                      325, 350, 375, 400, 425, 450, 475, 500, 525, 540, 550, 575, 600, 625, 650, 675, 700,
                      750, 825, 900, 975, 1000, 1050, 1125, 1200, 1275, 1350, 1425, 1500, 1575, 1650, 1725,
                      1800, 1875, 1950, 2025, 2100, 2175, 2250, 2325, 2400, 2475, 2550, 2700, 3000,
                      3400, 2450, 3500, 3900, 3950, 3999  
]).
pgvzfuti

pgvzfuti3#

Erlang解决方案,使用@Rajat所示的算法:

1> Conv = [{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"}].
[{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"}]
2> ToR_ = fun ToR_(0,_,Acc) -> Acc; ToR_(X,C=[{N,S}|T],Acc) -> case X div N of 0 -> ToR_(X,T,Acc); _ -> ToR_(X-N,C,Acc ++ S) end end.
#Fun<erl_eval.18.97283095>
3> ToR = fun(X) when X > 0, X < 5000 -> ToR_(X,Conv,[]) end.
#Fun<erl_eval.44.97283095>
4> ToR(25).                                                 
"XXV"
5> ToR(2098).                                                                                                                            
"MMXCVIII"
zpgglvta

zpgglvta4#

I don't know Erlang but this recursive Python version may help:

romVL = [(1000,"M"),(500,"D"),(100,"C"),(50,"L"),(10,"X"),(5,"V"),(1,"I")]
def int2rom(N,i=0):
    if not N: return ""
    V0,L0 = romVL[i]
    k,R   = divmod(N,V0)
    for V1,L1 in romVL[-1:i:-1]:                      # subtractive
        if 2*V1<V0 and R-V0+V1 in range(V1):
            return L0*k+L1+L0 + int2rom(R-V0+V1,i+1)
    return L0*k+int2rom(R,i+1)                        # additive

output:

int2rom(199)  'CIC'

int2rom(1938) 'MCMXXXVIII'

int2rom(1988) 'MLMXXXVIII'

int2rom(1999) 'MIM'

int2rom(2019) 'MMXIX'

The way it works is by dealing with one order of magnitude at each recursion level. The function generates the appropriate number of letters ( k = N//V0 from divmod) and recurses for the remainder ( R ) of the number ( int2rom(R,i+1) ).
For example: 2350 --> MM,350 --> CCC,50 --> L,0 :: MMCCCL
The subtractive part is handled after figuring out the number of letters but before sending the remainder down the recursion. It starts from the smallest order of magnitude and goes up to the current letter ( for V1,L1 in romVL[-1:i:-1] ). The first subtractive value that leaves a number smaller than itself ( R-V0+V1 in range(V1) ) is used and the recursion goes down from the remainder of the current letter minus the subtracted letter int2rom(R-V0+V1,i+1) .
For example: 296 --> CC,97 ... VC,1 --> II,0 :: CCVCII
In this case, after choosing to use CC (200) and before recursing for smaller letters, the function tries to see if it can use any ?C to consume a larger part of the remaining value (96). It first tries with 'I', but IC is 99 so it is too large, then VC which is 95 and would leave 2 as the remainder (which is smaller than the value of V). Now the remainder is 2 and the next level of recursions converts it to II.
There is one exception to the subtractive part which is that it needs to avoid subtracting a letter that could simply be used directly at the next level. For example 26 should not be converted to XXVXI because we can use V directly to get XXVI. To avoid this, letters that have a value exactly half of the current letter are excluded from the subtractive process (i.e. VX, LC, DM) using 2*V1<V0
Note that you can apply the subtractive parts directly in the romVL list ahead of time and only keep the additive logic in the function. This makes the mapping list larger and adds extra levels of recursion but it allows for a much simpler function implementation.

romVL = [999, 'IM', 995, 'VM', 990, 'XM', 950, 'LM', 900, 'CM', 500, 'D', 499, 'ID', 495, 'VD', 490, 'XD', 450, 'LD', 400, 'CD', 100, 'C', 99, 'IC', 95, 'VC', 90, 'XC', 50, 'L', 49, 'IL', 45, 'VL', 40, 'XL', 10, 'X', 9, 'IX', 5, 'V', 4, 'IV', 1, 'I']

def int2rom(N,V=1000,L="M",*rest):
    return N//V*L + int2rom(N%V,*rest or romVL) if N else ""

相关问题