In römische Zahl konvertieren!

13

Ihre Aufgabe ist es, eine bestimmte positive ganze Zahl von einer arabischen in eine römische Zahl umzuwandeln .

Schwierig wird es, wenn man bis 4000 zählt.

Die Römer taten dies, indem sie eine Linie über einem Symbol einfügten, um dieses Symbol mit zu multiplizieren 1 000. Überstriche können in ASCII jedoch nicht genau angezeigt werden. Außerdem gibt es doppelte Überstriche, mit denen ein Symbol multipliziert werden kann 1 000 000, und dreifache Überstriche, mit denen ein Symbol multipliziert werden kann 1 000 000 000, usw.

Aus diesem Grund habe ich mich entschieden, Klammern zu verwenden, um Überstriche zu ersetzen.

Die Symbole können einzeln in Klammern gesetzt werden. Beispielsweise sind beide (VI)und (V)(I)gültige Darstellungen von 6 000. (V)Mist auch eine gültige Darstellung von 6000.

(I)ist eine gültige Darstellungsweise 1 000.

Testfälle

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

Wertung

Das ist . Kürzester Code in Bytes gewinnen.

Undichte Nonne
quelle
1
Die Rechtfertigung dafür, warum dies kein Duplikat ist, wirft die Spezifikation durcheinander. Es wäre besser, ohne es IMO.
Mego
Wo würde ich die Begründung hinzufügen?
Undichte Nonne
1
Lass es aus. Wenn jemand fragt, ob es sich um ein Duplikat handelt, können Sie die Diskussion in Kommentaren oder im Chat führen.
Mego
@Mego Fertig. :-)
Undichte Nonne
Ist (IV)eine akzeptable Darstellung von 4000?
Neil

Antworten:

9

Mathematica, 67 Bytes

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

Vermeidet alle Probleme, Mindem die Eingabe in Basis 1000 konvertiert und jede Ziffer einzeln mit konvertiert wird RomanNumeral. Dann falten wir sie zusammen, indem wir sie von (...)links einfügen .

Leider stellt Mathematica Nullen dar, so Ndass wir diese loswerden müssen.

Martin Ender
quelle
1
verdammt mathematica mit seinen eingebauten für alles> :(
OldBunny2800
1
@ OldBunny2800 Ich würde mich wundern, wenn dies von keiner der Golfsprachen übertroffen würde.
Martin Ender
@ OldBunny2800 Und es kostet echtes Geld, um es zu bekommen. Das ist schlecht.
Erik der Outgolfer
@ Martinbüttner ich dachte einfach RomanNumeralgeht das?
Undichte Nonne
1
@KennyLau Es gibt MMMMfür aus 4000, es fängt nur an zu spezifizieren 5000(und dann bekommst du das gleiche Problem für 4000000usw.). Auch dann werden Überstriche anstelle von Klammern verwendet. Wenn Sie damit einverstanden sind, sollten Sie dies in der Herausforderungsspezifikation angeben.
Martin Ender
7

JavaScript (ES6), 136 Byte

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

Bei Zahlen unter 4000 wird jeder römische "Buchstabe" so oft wie möglich anhand der Liste der römischen "Buchstaben" und ihrer Dezimalwerte wiederholt. Ansonsten baut rekursiv die Antwort aus Division und Modulo mit 1000 auf. Zum Glückrepeat abgeschnitten, sodass ich es nicht selbst tun muss.

Neil
quelle
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))))))

Ungolfed

(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))))))

Tests

Zwei Tests ergeben andere Ergebnisse als die aus der Frage:

(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"))
Core-Dump
quelle
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=")")

Es ist so gut wie nicht die beste Option, aber ich denke, die Idee sollte dieser ziemlich ähnlich sein.

Masclins
quelle
1

Python, 188, 194

-6 Bytes vor dem Entfernen von Leerzeichen

Diese Herausforderung brachte mich zu dem Zeitpunkt zurück, als ich das Programmieren lernte ...

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

Es ist vielleicht nicht die kürzeste Lösung, aber ich hatte Spaß daran, dieses Problem zu lösen.

Versuch es!

Herr Public
quelle
1

Ruby, 137 134 130 Bytes

Rekursive Funktion, die die Zeichenfolge zurückgibt. Ich versuche, die Ziffernkodierungen, wenn möglich, ein bisschen genauer abzuspielen, bin mir aber nicht sicher, wie.

Hoppla, es ist praktisch ein direkter Port von Neils ES6-Antwort.

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]}"}
Wert Tinte
quelle
1

Ruby, 185 161 144 Bytes

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)}

Über ein Jahr nach dem ursprünglichen Post habe ich etwas über Golf gelernt.

Vielen Dank an Value Ink für Ihre wertvollen Kommentare.

MegaTom
quelle
gsubkann einen String als erstes Argument nehmen, wodurch das Ersetzen eines Regex-Musters s.gsub! x,yentfällt , da dies automatisch erfolgt. Ansonsten können Sie wahrscheinlich einfach auf die Zuweisung Ihres aArrays verzichten, da Sie es nur einmal verwenden, und es direkt in den each_sliceAnruf einfügen.
Wert Tinte
"IVXXLCCDM".scan(/(.)(.)(.)/){|x,b,c|...funktioniert auch
Value Ink
Auch r[x]ist funktional äquivalent zu r.(x)wann immer Stabby Lambdas beteiligt sind
Value Ink
@ ValueInk danke. Dieser r[x]Trick wird für alle meine futer rekursiven Golf in Ruby nützlich sein!
MegaTom
1

TCL 134 Bytes

proc f r {
set 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+}
expr [string map $map $r]0}

Versuchen Sie es hier: https://rextester.com/BJC92885

Chau Giang
quelle