ローマ数字に変換!


13

あなたの仕事は、与えられた正の整数をアラビア数字からローマ数字に変換することです。

4000を数えると事態は難しくなります。

ローマ人は、シンボルの上に線を追加して、そのシンボルをで乗算することでこれを行いました1 000。ただし、上線はASCIIでは正確に表示できません。また、シンボルを乗算する二重上線があり1 000 000、次にシンボルを乗算する三重上線1 000 000 000などがあります...

そのため、括弧を使用して上線を置き換えることにしました。

シンボルは括弧内に個別に配置できます。たとえば、(VI)(V)(I)は両方ともの有効な表現です6 000(V)M6000の有効な表現でもあります。

(I)はを表す有効な方法です1 000

テストケース

Input: 1
Output: I
Input: 2
Output: II
Input: 3
Output: III
Input: 4
Output: IV
Input: 15
Output: XV
Input: 40
Output: XL
Input: 60
Output: LX
Input: 67
Output: LXVII
Input: 400
Output: CD
Input: 666
Output: DCLXVI
Input: 3000
Output: MMM
Input: 3999
Output: MMMCMXCIX
Input: 4000
Output: M(V)
Input: 4999
Output: M(V)CMXCIX
Input: 6000
Output: (VI)
Input: 6000000
Output: ((VI))
Input: 6006000
Output: ((VI)VI)
Input: 6666666666
Output: (((VI)DCLXVI)DCLXVI)DCLXVI

得点

これはです。バイト単位の最短コードが勝ちます。


1
これが重複ではない理由の正当性は、仕様を混乱させます。IMOがなければより良いでしょう。
メゴ

正当化をどこに追加しますか?
リーキー修道女

1
はなれる。誰かが重複しているかどうか質問する場合は、コメントまたはチャットで議論してください。
メゴ

@Mego完了。:-)
リーキー修道女

である(IV)4000の許容表現は?
ニール

回答:


9

Mathematica、67バイト

Fold["("<>#<>")"<>#2&,RomanNumeral[#~IntegerDigits~1000]/."N"->""]&

M入力を基数1000に変換し、で各桁を個別に変換することにより、すべての問題を回避しRomanNumeralます。次に(...)、左から挿入して折ります。

残念ながら、Mathematicaはゼロを表すNため、それらを取り除く必要があります。


1
すべてのための組み込みのくそ
った

1
@ OldBunny2800とにかく、これがゴルフの言語のいずれにも負けなかったら驚かされるでしょう。
マーティンエンダー

@ OldBunny2800そして、それを手に入れるには本当のお金がかかります。それは良くないね。
エリックアウトゴルファー

@MartinBüttner単純にRomanNumeralできると思った?
リーキー修道女

1
@KennyLauのために出力MMMM4000、仕様で動作するように5000なります(その後、同じ問題が発生する4000000など)。それでも、括弧の代わりにオーバーバーを使用します。それでよければ、チャレンジ仕様でそう言うべきです。
マーティンエンダー

7

JavaScript(ES6)、136バイト

f=n=>n<4e3?"M1000CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1".replace(/(\D+)(\d+)/g,(_,r,d)=>r.repeat(n/d,n%=d)):`(${f(n/1e3)})`+f(n%1e3)

4000未満の数字の場合、ローマ字の「文字」のリストとその10進値を使用して、ローマ字の「文字」をできるだけ多く繰り返します。それ以外の場合、除算とモジュロからの答えを1000で再帰的に作成します。幸いなことにrepeat切り捨てられるので、自分で行う必要はありません。


3

Common Lisp、108

(defun p(n)(if(> n 0)(if(< n 4000)(format()"~@R"n)(format()"(~A)~@[~A~]"(p(floor n 1000))(p(mod n 1000))))))

非ゴルフ

(defun p(n)
  (if (> n 0)
      (if (< n 4000)

          ;; Built-in Roman formatter (between 1 and 3999)
          (format () "~@R" n)

          ;; Divide N by 1000, as 1000*Q + R.
          ;; First print (p Q) in parentheses (recursively)
          ;; Then, if it is not NIL, the remainder R.
          (format () "(~A)~@[~A~]"
                  (p (floor n 1000))
                  (p (mod n 1000))))))

テスト

2つのテストは、質問からのものとは異なる出力を提供します。

(loop for (in out) in '((1 "I")
                        (2 "II")
                        (3 "III")
                        (4 "IV")
                        (15 "XV")
                        (40 "XL")
                        (60 "LX")
                        (67 "LXVII")
                        (400 "CD")
                        (666 "DCLXVI")
                        (3000 "MMM")
                        (3999 "MMMCMXCIX")
                        (4000 "M(V)")
                        (4999 "M(V)CMXCIX")
                        (6000 "(VI)")
                        (6000000 "((VI))")
                        (6006000 "((VI)VI)")
                        (6666666666 "(((VI)DCLXVI)DCLXVI)DCLXVI"))
   for computed = (p in)
   unless (string= out computed)
   collect (list in out computed))

=> ((4000 "M(V)" "(IV)")
    (4999 "M(V)CMXCIX" "(IV)CMXCIX"))

2

R、134

m=1000;x=scan();while(x[1]>=m)x=c(floor(x[1]/m),x[1]%%m,x[-1]);cat(rep("(",length(x)),sep="");cat(as.character(as.roman(x)),sep=")")

それはほとんど最良の選択肢ではありませんが、アイデアはこれにかなり似たものになるはずだと思います。


1

パイソン、188 194

空白を削除してから-6バイト

この挑戦は、私が最初にプログラミングを学んでいた頃に戻ってきました...

def f(x,s=zip("M CM D CD C XC L XL X IX V IV I".split(),[1e3,900,500,400,100,90,50,40,10,9,5,4,1])):
 r=""if x<4e3else"("+f(x/1e3)+")";x%=1e3
 for a,b in s:
    while x>=b:r+=a;x-=b
 return r

それは最短の解決策ではないかもしれませんが、私はこの問題をゴルフで楽しんでいました。

やってみよう!


1

ルビー、137の 134 130バイト

文字列を返す再帰関数。可能であれば、数字のエンコードをもう少し掘り下げようとしていますが、どうすればよいかわかりません。

おっと、これは実質的に@NeilのES6回答の直接的なポートです。

f=->x{(x<t=1e3)?"CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1".gsub(/(\D+)(\d+)/){v=$2.to_i;s=x/v;x%=v;$1*s}:"(#{f[x/t]})#{f[x%t]}"}

1

Ruby、185161144バイト

r=->i{i>(t=1e3)? "(#{r[i/t]})"+r[i%t]:(s=?I*i;"IVXXLCCDM".scan(/(.)(.)(.)/){|x,y,z|{x*5=>y,x*4=>x+y,y*2=>z,y+x+y=>x+z}.map{|x,y|s.gsub!x,y}};s)}

最初の投稿から1年以上経って、ゴルフについて何かを学んだと思います。

貴重なコメントをありがとうございました。


gsub文字列を最初の引数として使用できs.gsub! x,yます。これは、自動的に行われるため、正規表現パターンへの置換の必要性を排除します。それ以外は、a配列を一度だけ使用して、each_slice呼び出しに直接配置するので、おそらく配列の割り当てを忘れることができます。
バリューインク

"IVXXLCCDM".scan(/(.)(.)(.)/){|x,b,c|...も動作します
バリューインク

またr[x]、機能的なr.(x)ラムダが関係する場合と機能的に同等です
値インク

@ValueInkありがとう。このr[x]トリックは、ルビーのすべてのfuter再帰ゴルフに役立つでしょう!
メガトム

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.