Преобразовать в римскую цифру!


13

Ваша задача - преобразовать данное положительное целое число из арабской цифры в римскую цифру.

Все становится сложнее, если считать до 4000.

Римляне сделали это, добавив строку над символом, чтобы умножить этот символ на 1 000. Однако в ASCII обводки не отображаются точно. Кроме того, существуют двойные пометки для умножения символа на 1 000 000, а затем тройные пометки для умножения символа на 1 000 000 000и т. Д.

Поэтому я решил использовать круглые скобки, чтобы заменить подчеркивания.

Символы могут быть индивидуально помещены в скобки. Например, оба (VI)и (V)(I)являются действительными представлениями 6 000.(V)Mтакже является действительным представлением 6000.

(I) это правильный способ представлять 1 000 .

Testcases

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
Обоснование того, почему это не дубликат, сбивает с толку спецификации. Было бы лучше без него ИМО.
Мего

Куда бы я добавил обоснование?
Утренняя монахиня

1
Пропусти это. Если кто-то спрашивает, является ли он дубликатом, обсудите это в комментариях или в чате.
Мего

@ Мего Готово. :-)
Дрянная Монахиня

Является (IV)ли приемлемое представление 4000?
Нил

Ответы:


9

Mathematica, 67 байт

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

Предотвращает все проблемы Mпутем преобразования ввода в базу 1000 и преобразования каждой цифры отдельно с помощью RomanNumeral. Затем мы складываем их, вставляя (...)слева.

К сожалению, Mathematica представляет нули, Nпоэтому мы должны избавиться от них.


1
чертовски mathematica с его встроенными
функциями

1
@ OldBunny2800 Я был бы удивлен, если бы это все равно не было побито ни одним из языков игры в гольф.
Мартин Эндер

@ OldBunny2800 И это стоит реальных денег, чтобы получить его. Плохо.
Эрик Outgolfer

@ MartinBüttner Я думал, просто RomanNumeralможет это сделать?
Утренняя монахиня

1
@KennyLau Он выводит MMMMдля 4000, он только начинает работать по спецификации 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 повторяется каждая римская «буква» столько раз, сколько возможно, используя список римских «букв» и их десятичных значений. В противном случае рекурсивно строит ответ от деления и по модулю с 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))))))

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

тесты

Два теста дают разные результаты, чем те, которые приведены в вопросе:

(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's 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

Рубин, 185 161 144 байта

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

Спустя год после первоначального поста, я думаю, что узнал кое-что о гольфе.

Спасибо Value Ink за ваши ценные комментарии.


gsubможет принимать строку в качестве первого аргумента, устраняя необходимость в подстановках в шаблоне регулярных выражений, поскольку s.gsub! x,yделает это автоматически. Кроме этого, вы, вероятно, можете просто отказаться от назначения вашего aмассива, поскольку вы используете его только один раз и вставляете его непосредственно в each_sliceвызов.
Value Ink

"IVXXLCCDM".scan(/(.)(.)(.)/){|x,b,c|...тоже работает
Value Ink

Кроме того r[x], функционально эквивалентен тому, что r.(x)когда-либо участвуют колбасные лямбды
Value Ink

@ValueInk спасибо. Этот r[x]трюк будет полезен всем моим рекурсивным гольфам в рубине!
MegaTom

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.