それらの貪欲なローマ人!


30

厳密に正の整数を指定すると、加算ルールのみを使用して、可能な限り短いローマ数字を返します。出力はMDCLXVI、その順序の各文字のゼロ個以上で構成する必要があります。14したがって、番号はXIIIIでなくでなければなりませんXIV

文字の数値は、M= 1000、D= 500、C= 100、L= 50、X= 10、V= 5、I= 1です。

3III

4 → IIII

9VIIII

42XXXXII

796DCCLXXXXVI

2017MMXVII

16807MMMMMMMMMMMMMMMMDCCCVII


1
あなたはできるようにする慈悲深い質問者がいる4 -> IIII9 -> VIIIIも代わりのようIX
魔法のタコUr


@MagicOctopusUrn VIIIIは9の唯一の許可された出力です。
Adám17年

@Adámは、4と9のルールが同じであるため、これを例として追加することもできると指摘していました。
魔法のタコUr

回答:


12

平易な英語1059 1025 678 641 451 399バイト

エラートラップを削除して34バイトを節約しました。その後、ゴルフで384バイトを節約しました。次に、分割操作と追加操作(「z」)を組み合わせて新しい操作(「p」)にすることにより、190バイトを節約しました。その後、ゴルフで52バイト節約しました。

A s is a string.
To p a r remainder a s a x string a n number:
If the x is "", exit.
Divide the r by the n giving a q quotient and the r.
Fill a t s with the x's first's target given the q.
Append the t to the s.
To convert a r number to a s:
p the r the s "M" 1000.
p the r the s "D" 500.
p the r the s "C" 100.
p the r the s "L" 50.
p the r the s "X" 10.
p the r the s "V" 5.
p the r the s "I" 1.

これは、最終コードの未使用バージョンと、負の数のエラートラップです。

A roman numeral is a string.

To process a remainder given a roman numeral and a letter string is a number:
  If the letter is "", exit.
  Divide the remainder by the number giving a quotient and the remainder.
  Fill a temp string with the letter's first's target given the quotient.
  Append the temp string to the roman numeral.

To convert a number to a roman numeral:
  If the number is negative, exit.
  Put the number in a remainder.
  Process the remainder given the roman numeral and "M" is 1000.
  Process the remainder given the roman numeral and "D" is  500.
  Process the remainder given the roman numeral and "C" is  100.
  Process the remainder given the roman numeral and "L" is   50.
  Process the remainder given the roman numeral and "X" is   10.
  Process the remainder given the roman numeral and "V" is    5.
  Process the remainder given the roman numeral and "I" is    1.

10
待って、これはプログラミング言語ですか?
アダム

3
@Adam-はい。平易な英語は、コンパイル、実行、そしてすべてです。ソースコードとIDEはgithub.com/Folds/english
Jasper

1
でもゴルフをやる-結局のところ、これは言語のショーケースではなくコードゴルフです。
-Sanchises

2
だから、これはあなたの仕事を外部委託したくない場合に使用する言語ですか?
corsiKa

@corsiKa-笑!十分な量を使用(およびライブラリに追加)し始めて、クリティカルマスを達成した場合のみ。
ジャスパー

5

APL(Dyalog)25 22バイト

'MDCLXVI'/⍨(0,62 5)∘⊤

オンラインでお試しください!


ニース、そして基本的に私が念頭に置いていた解決策。ただし、/reshape ()の代わりにreplicate()を使用して、それぞれとcatenate-reduction(¨および,/)を切り取ることができます。
アダム

また、tradfn本体に変換して入力()を取得し、通勤()を使用して括弧を削除して構成()することができます。
アダム

感謝しますが、2番目のコメントはどういう意味ですか?バイト数を増やすことなくこれを行う方法は考えられません
-TwiNight


1
関数をカウントするか、関数を囲む場合を除き、スニペットになります{}∇f∇
-TwiNight

5

網膜57 42バイト

単項に変換してから、Isの束をより高い宗派で順番に欲張りに置き換えます。

.*
$*I
I{5}
V
VV
X
X{5}
L
LL
C
C{5}
D
DD
M

オンラインで試す

Martinのおかげで15バイト節約


それはとても賢いです。
アダム

7
逆に言うと、はるかに短くなります:tio.run
マーティン・エンダー

Iユニットとして使用して単項で入力を取得できませんでしたか?
アダム

2
@AdámRetinaが整数入力を簡単に処理できるようになったことを考えると、それを行うのはちょっと安いと思います。
mbomb007

5

Python 2、64バイト

f=lambda n,d=5,r='IVXLCD':r and f(n/d,7-d,r[1:])+n%d*r[0]or'M'*n

オンラインでお試しください!

貪欲に最大の部分を取り、最初から出力文字列を作成するのではなく、最後から出力文字列を作成します。例えば、多数Iのでありn%5、その後の数Vのであるn/5%2、というように。これは、5と2が交互に連続する比率の混合ベース変換です。

これは反復的な同等物です:

Python 2、68バイト

n=input();s='';d=5
for c in'IVXLCD':s=n%d*c+s;n/=d;d^=7
print'M'*n+s

オンラインでお試しください!

M何より大きな数字がありませんようにそれらの任意の数が存在する可能性があるため、別々に処理することの必要性。そのため、他の場所の値が割り当てられた後、残りの値はに変換されMます。

比較のために、貪欲な戦略(69バイト):

Python 2、69バイト

f=lambda n,d=1000,r='MDCLXVI':r and n/d*r[0]+f(n%d,d/(d%3*3-1),r[1:])

オンラインでお試しください!

現在の数字の値をd2または5で除算して、次の数字を生成します。の値は、d%3どちらかd%3==12示しています。およびの場合d%3==2、5で除算します。


4

Mathematica、81バイト

Table@@@Thread@{r=Characters@"MDCLXVI",#~NumberDecompose~FromRomanNumeral@r}<>""&

値を明示的に使用し、対応する数字を導出すると、1バイト長くなります。

Table@@@Thread@{RomanNumeral[n={1000,500,100,50,10,5,1}],#~NumberDecompose~n}<>""&

1
ナイス!:FromRomanNumeral@r
DavidC

4

エクセル、236の 193 161バイト

@ BradCのおかげで43バイト節約

この時点で、答えは本当に@ BradCに完全に属します。さらに32バイトが保存されました。

=REPT("M",A1/1E3)&REPT("D",MOD(A1,1E3)/500)&REPT("C",MOD(A1,500)/100)&REPT("L",MOD(A1,100)/50)&REPT("X",MOD(A1,50)/10)&REPT("V",MOD(A1,10)/5)&REPT("I",MOD(A1,5))

フォーマット済み:

=REPT("M",A1/1E3)
    &REPT("D",MOD(A1,1E3)/500)
    &REPT("C",MOD(A1,500)/100)
    &REPT("L",MOD(A1,100)/50)
    &REPT("X",MOD(A1,50)/10)
    &REPT("V",MOD(A1,10)/5)
    &REPT("I",MOD(A1,5))

あなたは置き換えることによって、いくつかを節約できますCONCATENATE&、各要素の間、およびQUOTIENT持ちますINT(A/B)
BradC

さらに2つの節約:整数ではない場合、REPTすでに数値が切り捨てられていることが判明するため、それぞれを削除することでさらに30バイトを節約できますINT()。両方1000を置き換えることでさらに2を節約します1E3(ただし、ExcelはEnterキーを押した後はそのままにしたくないようです)。
BradC

ええ、1E3行動を見ました。回答が更新されました。
ヴェルニッシュ

3

Perl 5、66バイト

65バイトのコード+ -pフラグ。

$s=1e3;for$@(MDCLXVI=~/./g){$\.=$@x($_/$s);$_%=$s;$s/=--$|?2:5}}{

オンラインでお試しください!

バイトカウントを変更せずMDCLXVI=~/./gに、M,D,C,L,X,V,I; に置き換えることができます。と--$|?2:5によって$|--*3+2

はるかに長い(99バイト)、次のものがあります。

$_=M x($_/1e3).D x($_%1e3/500).C x($_%500/100).L x($_%100/50).X x($_%50/10).V x($_%10/5).I x($_%5)

3

CJam35 28バイト

マーティン・エンダーのおかげで-7バイト

q~{5md\2md\}3*]W%"MDCLXVI".*

オンラインでお試しください!

説明

q~         e# Read and eval input (push the input as an integer).
{          e# Open a block:
 5md\      e#  Divmod the top value by 5, and bring the quotient to the top.
 2md\      e#  Divmod that by 2, and bring the quotient to the top.
}3*        e# Run this block 3 times.
]W%        e# Wrap the stack in an array and reverse it. Now we've performed the mixed-base
           e# conversion.
"MDCLXVI"  e# Push this string.
.*         e# Element-wise repetition of each character by the numbers in the other array.
           e# Implicitly join and print.

3

C#、127バイト

f=n=>n>999?"M"+f(n-1000):n>499?"D"+f(n-500):n>99?"C"+f(n-100):n>49?"L"+f(n-50):n>9?"X"+f(n-10):n>4?"V"+f(n-5):n>0?"I"+f(n-1):""

再帰を使用した純粋にハードコードされた三項ステートメント。

フル/フォーマット済みバージョン:

using System;

class P
{
    static void Main()
    {
        Func<int, string> f = null;
        f = n => n > 999 ? "M" + f(n - 1000)
                         : n > 499 ? "D" + f(n - 500)
                                   : n > 99 ? "C" + f(n - 100)
                                            : n > 49 ? "L" + f(n - 50)
                                                     : n > 9 ? "X" + f(n - 10)
                                                             : n > 4 ? "V" + f(n - 5)
                                                                     : n > 0 ? "I" + f(n - 1)
                                                                             : "";

        Console.WriteLine(f(3));
        Console.WriteLine(f(4));
        Console.WriteLine(f(42));
        Console.WriteLine(f(796));
        Console.WriteLine(f(2017));
        Console.WriteLine(f(16807));

        Console.ReadLine();
    }
}

n>0ただnです。
電卓

@CalculatorFeline C#ではintなく、に暗黙的にキャストすることはできませんbool
TheLethalCoder

それは残念です。
電卓

@CalculatorFelineええ、C#は型付けが強すぎて、時々それ自体がいいです。
TheLethalCoder

3

05AB1E29 26 25バイト

¸5n3×Rvćy‰ì}"MDCLXVI"Ss×J

オンラインでお試しください!

説明

¸                           # wrap input in a list
 5n                         # push 5**2
   3×                       # repeat it 3 times
     Rv                     # for each digit y in its reverse
       ć                    # extract the head of the list 
                            # (div result of the previous iteration, initially input)
        y‰                  # divmod with y
          ì                 # prepend to the list
           }                # end loop
            "MDCLXVI"S      # push a list of roman numerals
                      s×    # repeat each a number of times corresponding to the result
                            # of the modulus operations
                        J   # join to string

3

JavaScript(ES6)、81 75 69バイト

@JörgHülsermannの回答を移植してくれた@Neilのおかげで6バイト節約

@Shaggyのおかげで6バイト節約

n=>'MDCLXVI'.replace(/./g,(c,i)=>c.repeat(n/a,n%=a,a/=i%2?5:‌​2),a=1e3)

テストケース:


1
メソッドn%=x内でを移動しrepeatて数バイトを節約できるはずです。
シャギー

1
参考までに、PHP回答のポートはたった69バイトですn=>'MDCLXVI'.replace(/./g,(c,i)=>c.repeat(n/a,n%=a,a/=i%2?5:2),a=1e3)
ニール

@Neilに感謝します。投稿を更新しました。私が再訪したかったハードコーディングされた配列を削除します
クレイグ・エア


2

Pythonの3100 97 96 94 93の91の 90バイト

  • 保存された4 + 2バイト:の使用def; デフォルトパラメータとしての配列は、インデントスペースを減らしました。不要な変数宣言が削除されました
  • @shooqieは1バイトのa%=速記を保存しました
  • 2バイト節約:再配置され、中括弧(a//i)が削除されました
  • @Wondercricketは1バイトを節約しました。デフォルトのパラメーターから、[]インデント1つ分のコストで削除された関数内に配列を移動し、1バイトを節約しました。
def f(a):
 b=1000,500,100,50,10,5,1
 for i in b:print(end=a//i*'MDCLXVI'[b.index(i)]);a%=i

オンラインでお試しください!


1
a%=iバイトが短い:)
shooqie

1
b関数内で変数として保存することにより、バイトを保存することもできます。これにより、ブラケットの必要性がb=1000,500,100,50,10,5,1
なくなり

2

Cubix、69 74 80バイト

/.UI,..N&..0\0&/52"IVXLCDM"U,r%ws;rr3tu;pw..u;qrUosv!s.u\psq,!@Us(0;U

オンラインでお試しください!

        / . U I
        , . . N
        & . . 0
        \ 0 & /
5 2 " I V X L C D M " U , r % w
s ; r r 3 t u ; p w . . u ; q r
U o s v ! s . u \ p s q , ! @ U
s ( 0 ; U . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

実行中

私はそれをもう少し圧縮することができましたが、特に上面には厄介なノーオペレーションがまだあります。

  • 52"IVXLCDM"U必要な除数と文字をスタックに配置します。5と2はdiv / mod値を減らすために使用され、文字は使用後に破棄されます。
  • UIN0/&0\&,/Uuが上面に戻り、入力を取得して1000をスタックにプッシュするための長いツアーを開始します。最初の分割が行われr、次のスニペットにuターンします。これは、節約するために検討していた領域でした。
  • ,r%ws;rrdivmodループの開始。整数除算、結果をmodで回転させ、スタックのトップを再配置して、入力、現在の除数、除算結果を減らします。
  • 3tus 現在のキャラクターを一番上に持ってきて、除算結果と入れ替えます。
  • !vsoUs(0;Uこれが印刷ループです。divの結果が0を超えている間、文字出力とスワップし、スワップバックし、デクリメントし、0をプッシュしてドロップします。0の場合、ポップスタック(除算結果を削除)およびキューブの周囲にリダイレクトします。
  • \u;pwpsq,!@Urq;u少しのリダイレクトで、これはスタックからキャラクターを削除し、5と2を一番上に持ってきて、それらを交換し、1つを押し下げます。残りは除数を減らすために使用されます。0になった場合は停止します。それ以外の場合は、5または2を下に押して、ループに入ります。

1

Mathematica、130バイト

(f=#~NumberDecompose~{1000,500,100,50,10,5,1};""<>{Flatten@Table[Table[{"M","D","C","L","X","V","I"}[[i]],f[[i]]],{i,Length@f}]})&



1

T-SQL、164バイト

SELECT REPLICATE('M',n/1000)+IIF(n%1000>499,'D','')
      +REPLICATE('C',n%500/100)+IIF(n%100>49,'L','')
      +REPLICATE('X',n%50/10)+IIF(n%10>4,'V','')
      +REPLICATE('I',n%5)
FROM t

読みやすくするためだけに改行が追加されています。

このバージョンはかなり長くなります(230文字)が、より「SQLに似た」感じがします。

DECLARE @ INT,@r varchar(99)=''SELECT @=n FROM t
SELECT'I's,1v INTO m
INSERT m VALUES('V',5),('X',10),('L',50),('C',100),('D',500),('M',1000)
L:
    SELECT @-=v,@r+=s 
    FROM m WHERE v=(SELECT MAX(v)FROM m WHERE v<=@)
IF @>0GOTO L
SELECT @r

すべてのchar-valueマッピングを含むテーブルmを作成し、最大値<=数値を見つけてループし、一致する文字を連結します。


1

Japt、34バイト

"IVXLCD"£%(U/=Y=v *3+2Y)îXÃw i'MpU

オンラインでテストしてください!

"IVXLCD"£    %(U/=Y=v  *3+2Y )îXÃ w i'MpU
"IVXLCD"mXY{U%(U/=Y=Yv *3+2,Y)îX} w i'MpU : Ungolfed
                                          : Implicit: U = input number
"IVXLCD"mXY{                    }         : Map each char X and its index Y in this string to:
                  Y=Yv *3+2               :   Set Y to 5 for even indexes, 2 for odd.
               U/=                        :   Divide U by this amount.
            U%(            ,Y)            :   Modulate the old value of U by 5.
                              îX          :   Repeat the character that many times.
                                          : This returns e.g. "IIVCCCD" for 16807.
                                  w       : Reverse the entire string.
                                    i'MpU : Prepend U copies of 'M' (remember U is now the input / 1000).
                                          : Implicit: output result of last expression

1

JavaScript(ES6)、65バイト

再帰関数。

f=(n,a=(i=0,1e3))=>n?a>n?f(n,a/=i++&1?5:2):'MDCLXVI'[i]+f(n-a):''

どうやって?

2番目の再帰呼び出しはf(n-a)実際に必要ですf(n-a,a)。2番目のパラメータを省略することによって、aおよびi(それぞれ1000と0に)再初期化されるたびに、新しいローマ数字は、最終結果に追加されます。これにより、必要以上の再帰が発生しますが、関数の結果は変わらず、2バイト節約されます。

テストケース


1

J26 23バイト

Adámのおかげで3バイト節約されました。

'MDCLXVI'#~(_,6$2 5)&#:

オンラインでお試しください!

APLの回答と同様に、基本的に同じことを答えます。

'MDCLXVI'#~(_,6$2 5)&#:
           (       )&#:   mixed base conversion from decimal
              6$2 5       2 5 2 5 2 5
            _,            infinity 2 5 2 5 2 5
                          this gives us e.g. `0 0 0 0 1 0 4` for input `14`
'MDCLXVI'#~               shape each according to the number of times on the right
                          this is greedy roman numeral base conversion

私がJを知っているわけではありませんが、なぜ#.inv代わりに#:
アダム

@Adám Ah, good point. I customarily use #.inv instead of #:, since something like 2 #: 4 is 0, whilst 2 #.inv 4 is 1 0 0
Conor O'Brien

Yeah, I do the same thing in APL. Now your solution is truly equivalent to the APL solution.
Adám

# is /; ~ is ; $ is ; & is ; #: is . The only difference is that you use infinity _ while you could use 0 like the APL answer.
Adám

@Adámフー、かっこいい。
コナーオブライエン

1

バッチ、164バイト

@set/pn=
@set s=
@for %%a in (1000.M 500.D 100.C 50.L 10.X 5.V 1.I)do @call:c %%~na %%~xa
@echo %s:.=%
@exit/b
:c
@if %n% geq %1 set s=%s%%2&set/an-=%1&goto c

STDINで入力を受け取ります。


1

Oracle SQL、456バイト

select listagg((select listagg(l)within group(order by 1)from dual start with trunc((n-nvl(n-mod(n,p),0))/v)>0 connect by level<=trunc((n-nvl(n-mod(n,p),0))/v)))within group(order by v desc)from (select 2849n from dual)cross join(select 1000v,null p,'m'l from dual union select 500,1000,'d'from dual union select 100,500,'c'from dual union select 50,100,'l'from dual union select 10,50,'x'from dual union select 5,10,'v'from dual union select 1,5,'i'from dual)

出力:

mmdcccxxxxviiii

入力番号(2849)が含まれているため、行の実際のサイズは460バイトです。

ゴルフをしていない:

select listagg(
            (select listagg(l, '') within group(order by 1) 
             from dual 
             start with trunc((n-nvl(p*trunc(n/p),0))/v) > 0 
             connect by level <= trunc((n-nvl(p*trunc(n/p),0))/v) )
        ) within group(order by v desc)
from (select 2348 n
    from dual
) cross join (
    select 1000v, null p, 'm' l from dual union 
    select 500, 1000, 'd' from dual union
    select 100, 500, 'c' from dual union
    select 50, 100, 'l' from dual union
    select 10, 50, 'x' from dual union
    select 5, 10, 'v' from dual union
    select 1, 5, 'i' from dual     
)

仕組み:より高い値の1(Mの無限大)で到達できる最大数を計算し、現在の文字の値とその結果の間で整数除算を行うことにより、必要な各文字の数を計算します。

たとえば、2348、何C秒必要ですか?trunc((2348-mod(2348,500))/100)= 3。

Then, I listagg that letter together 3 times (exploiting CONNECT BY to generate the 3 rows I need). Finally, I listagg everything together.

Kinda bulky, but most of it is the select from duals in the conversion table and I can't really do much about that...


0

Java (OpenJDK 8), 119 118 bytes

n->{String s="";for(int v[]={1,5,10,50,100,500,1000},i=7;i-->0;)for(;n>=v[i];n-=v[i])s+="IVXLCDM".charAt(i);return s;}

Try it online!

Saved a byte thanks to @TheLethalCoder


1
Can you declare v and i in the first for loop to save a byte?
TheLethalCoder

@TheLethalCoder Yes, most certainly. I was on a totally other idea at first that this didn't pass my internal review :p
Olivier Grégoire

0

Charcoal, 61 50 46 bytes

NνA⁰χWφ«W¬‹νφ«§MDCLXVIχA⁻νφν»A⁺¹χχA÷φ⎇﹪χ²¦²¦⁵φ

Try it online!

Explanation:

Nν                   Take input as number and assign it to ν
A⁰χ                  Let χ=0
Wφ«                  While φ>0 (φ has a predefined value of 1000)
    W¬‹νφ«               While v>=φ 
        §MDCLXVIχ             Take the char from string "MDCLXVI" at position χ
        A⁻νφν»               Let ν=ν-φ
    A⁺¹χχ                Increment χ
    A÷φ⎇﹪χ²¦²¦⁵φ        If χ is odd, divide φ by 5, else divide φ by 2
  • 4 bytes saved thanks to Neil, while I am still trying to figure out how to proceed with the second part of his comment.

1
Nν is one byte shorter than ANν, ¬‹ is one byte shorter than subtracting 1, and if you use ÷ (IntDivide) instead of (Divide) then you can use φ as the outer loop condition. However, I think you can get it down to 40 bytes by looping over MDCLXVI directly instead.
Neil

@Neil of course, silly me, trying to understand why there is no "greater or equal" operator when I could use "not less". Very clever trick the use of the integer division. Now allow me some time to think about the last part of your comment...
Charlie

I improved my string loop idea and posted it as a seprate answer along with a port of @xnor's Python answer, which turned out to be the same length.
Neil

0

C++, 272 Bytes

#include <cstdio>
#include <map>
std::map<int,char> m = {{1000,'M'},{500,'D'},{100,'C'},{50,'L'},{10,'X'},{5,'V'},{1,'I'}};
int main(){unsigned long x;scanf("%d",&x);for(auto i=m.rbegin();i!=m.rend();++i)while(x>=i->first){printf("%c", i->second);x=x-i->first;}return 0;}

0

C, 183 Bytes

#include <stdio.h>
int v[]={1000,500,100,50,10,5,1};
char*c="MDCLXVI";
int main(){int x;scanf("%d",&x);for(int i=0;i<sizeof v/sizeof(int);i++)for(;x>=v[i];x-=v[i])putc(c[i],stdout);}

Same algorithm as before, just using plain c arrays instead of an std::map, partially inspired by @xnor's answer and using a string to store the letters.



0

Common Lisp, 113 bytes

This is an anonymous function, returning the result as a string.

(lambda(value)(setf(values a b)(floor v 1000))(concatenate 'string(format()"~v,,,v<~>"a #\M)(format nil"~@:r"b)))

Ungolfed, with descriptive variable names and comments:

(defun format-roman (value)
  ;; Get "value integer-divided by 1000" and "value mod 1000"
  (setf (values n_thousands remainder) (floor value 1000))
  (concatenate 'string
               ;; Pad the empty string n_thousands times, using "M" as the 
               ;; padding character
               (format () "~v,,,v<~>" n_thousands #\M)
               ;; Format the remainder using "old-style" Roman numerals, i.e. 
               ;; numerals with "IIII" instead of "IV"
               (format nil "~@:r" remainder)))

CL has built-in Roman numeral formatter. Sadly it doesn't work for numbers larger than 3999.


0

Charcoal, 34 bytes

NςA²ξFMDCLXVI«×ι÷ςφA﹪ςφςA÷φξφA÷χξξ

Originally based on @CarlosAlego's answer. A port of @xnor's Python solution is also 34 bytes:

NθA⁵ξFIVXLCD«←×ι﹪θξA÷θξθA÷χξξ»←×Mθ

Edit: A port of @xnor's other Python solution turns out to be 33 bytes!

NθFMDCLXVI«×ι÷θφA﹪θφθA÷φ⁺׳﹪φ³±¹φ

Try it online! Link is to verbose version of code. Note that I've used ⁺׳﹪φ³±¹ instead of ⁻׳﹪φ³¦¹ because the deverbosifier is currently failing to insert the separator.


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