# Roman Numeral Converter Challenge

Roman Numeral Converter Challenge
0

#46

All done - a very basic approach from me:

var oneToNine = ["","I","II","III","IV","V","VI","VII","VIII","IX"];
var tens = ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"];
var hundreds = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"];
var thousands = ["M","MM","MMM"];

function convertToRoman(num) {

var numArr = num.toString().split("");

if (numArr.length === 1){

return oneToNine[num];
}

else if (numArr.length === 2){

return tens[numArr[0]] + oneToNine[numArr[1]];
}

else if (numArr.length === 3) {

return hundreds[numArr[0]]+tens[numArr[1]] + oneToNine[numArr[2]];
}

else if (numArr.length === 4){

return thousands[numArr[0]-1]+hundreds[numArr[1]]+tens[numArr[2]] + oneToNine[numArr[3]];
}

}

convertToRoman(1232);

#47

Mine may be the most inefficient solution.

function convertToRoman(num) {

thousandsDigit = parseInt(num / 1000);
hundredsDigit = parseInt((num / 100) % 10);
tensDigit = parseInt((num / 10) % 10);
onesDigit = parseInt(num % 10);

numDigits = [thousandsDigit, hundredsDigit, tensDigit, onesDigit];

// convert each number digit to Roman numeral
var romanNumber = "";
for (var i = 0; i < numDigits.length; i++) {
switch(numDigits[i]) {

case 1:
if (i === 3) {
romanNumber += "I"; // onesDigit
} else if (i === 2) {
romanNumber += "X"; // tensDigit
} else if (i === 1) {
romanNumber += "C"; // hundredsDigit
} else {
romanNumber += "M"; // thousandsDigit
}
break;

case 2:
if (i === 3) {
romanNumber += "II"; // onesDigit
} else if (i === 2) {
romanNumber += "XX"; // tensDigit
} else if (i === 1) {
romanNumber += "CC"; // hundredsDigit
} else {
romanNumber += "MM"; // thousandsDigit
}
break;

case 3:
if (i === 3) {
romanNumber += "III"; // onesDigit
} else if (i === 2) {
romanNumber += "XXX"; // tensDigit
} else if (i === 1) {
romanNumber += "CCC"; // hundredsDigit
} else {
romanNumber += "MMM"; // thousandsDigit
}
break;

case 4:
if (i === 3) {
romanNumber += "IV"; // onesDigit
} else if (i === 2) {
romanNumber += "XL"; // tensDigit
} else {
romanNumber += "CD"; // hundredsDigit
}
break;

case 5:
if (i === 3) {
romanNumber += "V"; // onesDigit
} else if (i === 2) {
romanNumber += "L"; // tensDigit
} else {
romanNumber += "D"; // hundredsDigit
}
break;

case 6:
if (i === 3) {
romanNumber += "VI"; // onesDigit
} else if (i === 2) {
romanNumber += "LX"; // tensDigit
} else {
romanNumber += "DC"; // hundredsDigit
}
break;

case 7:
if (i === 3) {
romanNumber += "VII"; // onesDigit
} else if (i === 2) {
romanNumber += "LXX"; // tensDigit
} else {
romanNumber += "DCC"; // hundredsDigit
}
break;

case 8:
if (i === 3) {
romanNumber += "VIII"; // onesDigit
} else if (i === 2) {
romanNumber += "LXXX"; // tensDigit
} else {
romanNumber += "DCCC"; // hundredsDigit
}
break;

case 9:
if (i === 3) {
romanNumber += "IX"; // onesDigit
} else if (i === 2) {
romanNumber += "XC"; // tensDigit
} else {
romanNumber += "CM"; // hundredsDigit
}
}
}

return romanNumber;
}

convertToRoman(36);

#48

After doing a horrible code first (it worked tho) I’ve decided to do it again and came out this way:

function convertToRoman(num) {

var arabic = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
var roman = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];

var number = num;
var rArray = [];

for (var i = 0; i < arabic.length; i++)
{
var occurrence = parseInt( number / arabic[i] );
number -= occurrence * arabic[i];
rArray.push(roman[i].repeat(occurrence));
}

return rArray.join("");
}

#49

Hmm here are some very nice solutions, hard coding the edge cases (e.g. 9er & 4er) is something I, don’t know why, avoided…

// roman numerals
var romanSymbs = {
1: 'I',
5: 'V',
10: 'X',
50: 'L',
100: 'C',
500: 'D',
1000: 'M'
};
var romanNums = Object.keys(romanSymbs);
var gtRoNumIndex = romanNums.length - 1;

// split num to decimal places
function splitNum (num) {
var numStr = num.toString();
var numSplits = [];
for (var index = numStr.length - 1, place = 0; index >= 0; --index, ++place) {
if (numStr[index] === '0') continue;
numSplits.push(numStr[index] * Math.pow(10, place));
}
return numSplits.reverse();
}

// test occurrence of 4 same symbols on the trot
var romanRegexp = [
/I{4,}/,
/V{4,}/,
/X{4,}/,
/L{4,}/,
/C{4,}/,
/D{4,}/
];
return romanRegexp.some(function (regexp) {
return regexp.test(symbStr);
});
}

function createRoman (num) {
/* src: http://turner.faculty.swau.edu/mathematics/materialslibrary/roman/
* Start by removing the largest Roman values first and subtracting the removed value until
* we have converted the entire value. We keep trying to remove a given Roman value until we cannot,
* then we try the next smaller one.
*/
var num_ = num;
var symbStr = '';
var index;

while (num_ > 0) {
for (index = gtRoNumIndex; index >= 0; --index) {
if (num_ - romanNums[index] >= 0) {
symbStr += romanSymbs[romanNums[index]];
num_ -= romanNums[index];
break;
}
}
}
// get nearest roman base
var minuend = romanNums.reduce(function (prev, curr) {
if ((Math.max(curr, num) - Math.min(curr, num)) < Math.max(prev, num) - Math.min(prev, num)) {
return curr;
} else {
return prev;
}
});
symbStr = romanSymbs[minuend];
while (minuend > num) {
for (index = gtRoNumIndex; index >= 0; --index) {
if (minuend - romanNums[index] >= num) {
symbStr = romanSymbs[romanNums[index]] + symbStr;
minuend -= romanNums[index];
break;
}
}
}
return symbStr;
} else {
return symbStr;
}
}

function convertToRoman (num) {
var splitNums = splitNum(num);
var symbs = splitNums.map(createRoman);
var symbsStr = symbs.join('');
return symbsStr;
}

#50

This one really made me think and use pen and paper to organise my thoughts. I used special html characters for numbers greater than 3999.

function convertToRoman(num) {
var keys = {
"1":["I", "X", "C", "M"],
"2":["II", "XX", "CC", "MM"],
"3":["III", "XXX", "CCC", "MMM"],
"4":["IV", "XL", "CD", "M&Uuml;"],
"5":["V", "L" , "D", "&Uuml;"],
"6":["VI", "LX", "DC", "&Uuml;M"],
"7":["VII", "LXX", "DCC", "&Uuml;MM"],
"8":["VIII", "LXXX","DCCC", "&Uuml;MMM"],
"9":["IX", "XC", "CM", "M&Yuml;"]
};

//Converts integer to string
var numStr = num.toString();
//Converts the arabic number into an array of strings
var numArray = numStr.split('');
var romArr = [];
var converted = [];

// Converts arabic array of stgrings into array of integers
numArray.forEach(function(a){
romArr.push(parseInt(a));
});

//Converts from arabic to roman by pairing indexOf with key
var ind = 0;
romArr.forEach(function(b){
var conv = "";

if (b === 0){

} else {
conv = keys[b.toString()][romArr.length - 1 - ind];
converted.push(conv);
console.log(converted);
}

console.log(ind);
ind++;
});

num = converted.join("");

return num;
}

#51

This was my solution to the challenge, but I also tried to make it into an actual web-page. Then I realized that it’s only converting correct up to 3999. So I ended up doing a bit more coding to get a real converter. Link to Github at the bottom. Still not sure if it’s correct though…

function convertToRoman(num) {
numString = num.toString();
numArray = numString.split("");

var positionOne = ["", “I”, “II”, “III”, “IV”, “V”, “VI”, “VII”, “VIII”, “IX”];
var positionTen = ["", “X”, “XX”, “XXX”, “XL”, “L”, “LX”, “LXX”, “LXXX”, “XC”];
var positionHundred = ["", “C”, “CC”, “CCC”, “CD”, “D”, “DC”, “DCC”, “DCCC”, “CM”];
var positionThousand = ["", “M”, “MM”, “MMM”, “MV”, “V”, “VI”, “VII”, “VIII”, “IX”];

if (numArray.length === 1) {
return positionOne[numArray];
} else if (numArray.length === 2) {
return positionTen[numArray[0]] + positionOne[numArray[1]];
} else if (numArray.length === 3) {
return positionHundred[numArray[0]] + positionTen[numArray[1]] + positionOne[numArray[2]];
} else if (numArray.length === 4) {
return positionThousand[numArray[0]] + positionHundred[numArray[1]] + positionTen[numArray[2]] + positionOne[numArray[3]];

}
}

https://pialise.github.io/romanNumeralConverter/

#52

Hi, I don’ think that my solution is the better solution, but I don’t see any solution like mine:

function convertToRoman(num) {
var arrayRoman = {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’};

var arrayAux = [1000, 100, 10, 1];
var arrayReturn = [];

for(var i = 0; i < arrayAux.length ; i++){

arrayReturn.push(arrayRoman[Math.floor(num / arrayAux[i]) * arrayAux[i] ]);

num = num%arrayAux[i];

}

return arrayReturn.join(’’);
}

#53

## my solution

function convertToRoman(num) {
let rom = ["I", "V", "X", "L", "C", "D", "M"],
snum = num.toString().split('').reverse().join(''),
res = [];
for (let i = 0, len = snum.length, n, r; i < len; i++){
r = i*2;
n = parseInt(snum[i]);
switch(n){
case 1:case 2:case 3:
res.unshift(rom[r].repeat(n));
break;
case 4:
res.unshift(rom[r]+rom[r+1]);
break;
case 5:
res.unshift(rom[r+1]);
break;
case 6:case 7:case 8:
res.unshift(rom[r+1]+(rom[r].repeat(n-5)));
break;
case 9:
res.unshift(rom[r]+rom[r+2]);
break;
case 10:
res.unshift(rom[r+2]);
break;
}
}
return res.join('');
}

#54

my not so elegant solution

function convertToRoman(num) {

var breakDown = [];
var tempStr = [];
var one = 'I',
five = 'V',
ten = 'X',
fifty = 'L',
hundred = 'C',
fiveHundred = 'D',
thousand = 'M';

if(num <= 10) {
breakDown.push(num);
} else if( num >= 1000) {
for (var x = 1000, temp1 = 0; x >= 1; x /= 10) {
if (num / x >= 1) {
temp1 = num % x;
breakDown.push(num - temp1);
num = temp1;

} else if(num < 10 && x === 1) {
breakDown.push(num);
} else {
breakDown.push(0);
}
}
} else if(num > 100 && num < 1000) {
for (var y = 100, temp2 = 0; y >= 1; y /= 10) {
if (num / y >= 1) {
temp2 = num % y;
breakDown.push(num - temp2);
num = temp2;

} else if(num < 10 && y === 1) {
breakDown.push(num);
} else {
breakDown.push(0);
}
}
} else {
for (var z = 10, temp3 = 0; z >= 1; z /= 10) {
if (num / z >= 1) {
temp3 = num % z;
breakDown.push(num - temp3);
num = temp3;

} else if(num < 10 && z === 1) {
breakDown.push(num);
} else {
breakDown.push(0);
}
}
}

for(var i = 0; i < breakDown.length; i++) {

if(breakDown[i] >= 1000) {
/* for(var j = 0; j < (breakDown[j] / 1000); j++) {
tempStr.push(thousand);
} */
switch(breakDown[i]) {
case 1000:
tempStr.push(thousand);
break;
case 2000:
tempStr.push(thousand + thousand);
break;
case 3000:
tempStr.push(thousand + thousand + thousand);
break;
case 4000:
tempStr.push(thousand + thousand + thousand + thousand);
break;
}
} else if(breakDown[i] === 1) {
tempStr.push(one);
} else if(breakDown[i] === 2) {
tempStr.push(one + one);
} else if(breakDown[i] === 3) {
tempStr.push(one + one + one);
} else if(breakDown[i] === 4) {
tempStr.push(one + five);
} else if(breakDown[i] === 5) {
tempStr.push(five);
} else if(breakDown[i] === 6) {
tempStr.push(five + one);
} else if(breakDown[i] === 7) {
tempStr.push(five + one + one);
} else if(breakDown[i] === 8) {
tempStr.push(five + one + one + one);
} else if(breakDown[i] === 9) {
tempStr.push(one + ten);
} else if(breakDown[i] === 10) {
tempStr.push(ten);
} else if(breakDown[i] === 20) {
tempStr.push(ten + ten);
} else if(breakDown[i] === 30) {
tempStr.push(ten + ten + ten);
} else if(breakDown[i] === 40) {
tempStr.push(ten + fifty);
} else if(breakDown[i] === 50) {
tempStr.push(fifty);
} else if(breakDown[i] === 60) {
tempStr.push(fifty + ten);
} else if(breakDown[i] === 70) {
tempStr.push(fifty + ten + ten);
} else if(breakDown[i] === 80) {
tempStr.push(fifty + ten + ten + ten);
} else if(breakDown[i] === 90) {
tempStr.push(ten + hundred);
} else if(breakDown[i] === 100) {
tempStr.push(hundred);
} else if(breakDown[i] === 200) {
tempStr.push(hundred + hundred);
} else if(breakDown[i] === 300) {
tempStr.push(hundred + hundred + hundred);
} else if(breakDown[i] === 400) {
tempStr.push(hundred + fiveHundred);
} else if(breakDown[i] === 500) {
tempStr.push(fiveHundred);
} else if(breakDown[i] === 600) {
tempStr.push(fiveHundred + hundred);
} else if(breakDown[i] === 700) {
tempStr.push(fiveHundred + hundred + hundred);
} else if(breakDown[i] === 800) {
tempStr.push(fiveHundred + hundred + hundred + hundred);
} else if(breakDown[i] === 900) {
tempStr.push(hundred + thousand);
} else {
tempStr.push('');
}

}
num = tempStr.join('');

return num;
}

convertToRoman(36);

#55

Not so compact but it works and it’s all original. Basically a bunch of if statements that reduces the num down as it progresses and at the same time builds up the roman numeral.

function convertToRoman(num) {

var romanNum = "";

if (num >= 1000){
var M = Math.floor(num/1000);
num = num - (M * 1000);
for (var z = 0; z < M; z++){
romanNum = romanNum.concat("M");
}
}

if (num < 1000 & num >= 900){
var CM = Math.floor(num/900);
num = num - (CM * 900);
romanNum = romanNum.concat("CM");
}

if (num >= 500){
num = num - 500;
romanNum = romanNum.concat("D");
}

if (num >= 100){
var C = Math.floor(num/100);
num = num - (C * 100);
for (var z = 0; z < C; z++){
romanNum = romanNum.concat("C");
}
}

if (num < 100 & num >= 90){
var XC = Math.floor(num/90);
num = num - (XC * 90);
romanNum = romanNum.concat("XC");
}

if (num >= 50){
num = num - 50;
romanNum = romanNum.concat("L");
}

if (num >= 40){
var XL = Math.floor(num/40);
num = num - (XL * 40);
romanNum = romanNum.concat("XL");
}

if (num >= 10){
var X = Math.floor(num/10);
num = num - (X * 10);
for (var z = 0; z < X; z++){
romanNum = romanNum.concat("X");
}
}

if (num < 10 & num >= 9){
var IX = Math.floor(num/9);
num = num - (IX * 9);
romanNum = romanNum.concat("IX");
}

if (num >= 5){
num = num - 5;
romanNum = romanNum.concat("V");
}

if (num == 4){
var IV = Math.floor(num/4);
num = num - (IV * 4);
romanNum = romanNum.concat("IV");
}

if (num >= 1){
var I = Math.floor(num/1);
num = num - (I * 1);
for (var z = 0; z < I; z++){
romanNum = romanNum.concat("I");
}
}

return romanNum;
}

#56

Really nice job. This is a clever approach. It’s listed here as the basic solution but ought to be swapped with the “intermediate” solution.

PS: here’s me getting an emoji badge:

#57

this was my solution. Not proud.

• Convert num to a string with leading 0s
• Slice to 4 places and split num into an array.
• Map array to return value, substituting corresponding roman numerals:
• e.g., 2 in ones place is romanArr[0][2]; in tens place maps to romanArr[1][2]
• Math.abs(index-(myNumber.length-1)) reverses array order… i.e., 0 index looks at 4th place
• Join and return
function convertToRoman(num) {
var myNumber = ("000"+num).slice(-4).split("");
var romanArr=[];
romanArr[0] = ["","I","II","III","IV","V","VI","VII","VIII","IX"];
romanArr[1] = ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"];
romanArr[2] = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"];
romanArr[3] = ["","M","MM","MMM","MV","V","VM","XMM","XMMM","MW"];
return myNumber.map( function(value,index) {
return romanArr[Math.abs(index-(myNumber.length-1))][value];
}).join("");
}
convertToRoman(3);

#58

function convertToRoman(num) {
var newArray = [];

while (num>999){
newArray.push(“M”);
num = num-1000;
}
while (num>499){
newArray.push(“D”);
num = num-500;
}
while (num>99){
newArray.push(“C”);
num = num-100;
}
while (num>49){
newArray.push(“L”);
num = num-50;
}
while (num>9){
newArray.push(“X”);
num = num-10;
}
while (num>4){
newArray.push(“V”);
num = num-5;
}
while (num>0){
newArray.push(“I”);
num–;
}
return newArray.join("").replace(/DCCCC/g, ‘CM’).replace(/CCCC/g, ‘CD’).replace(/LXXXX/g, ‘XC’).replace(/XXXX/g, ‘XL’).replace(/VIIII/g, ‘IX’).replace(/IIII/g, ‘IV’);
}

#59

Yeah, I had a hard coded version that I didn’t like so I tried something more algoruthmic:

\$(function(){

function convertToRoman(num) {
var romanNumeralChars = ["I", "V", "X", "L", "C", "D", "M"];  // array of RN symbols
var romanNumeral = []; // array to which we will push each symbol

var factor = Math.pow(10, power); // which "place" are we disecting
var base = power*2; // the index into romanNumeralChars for the "place"

if (num>=factor) { // is there any portion in this "place"
var top = Math.floor(num/factor); // lop off the portion of this "place" and reduce to a single digit
num -= top*factor; // remove that lopped off potion so we can continue later with the remainder

switch(top) {
case 1:
case 2:
case 3:
for (var j = 0 ; j < top ; j++) {
romanNumeral.push(romanNumeralChars[base]);
}
break;
case 4:
romanNumeral.push(romanNumeralChars[base]);
romanNumeral.push(romanNumeralChars[base+1]);
break;
case 5:
case 6:
case 7:
case 8:
romanNumeral.push(romanNumeralChars[base+1]);
for (var k = 0 ; k < (top - 5) ; k++) {
romanNumeral.push(romanNumeralChars[base]);
}
break;
case 9:
romanNumeral.push(romanNumeralChars[base]);
romanNumeral.push(romanNumeralChars[base+2]);
break;
} // switch
} // if

if (num < 0 || num > 3999 || !Number.isInteger(num)) { // making sure it's and integet between 0 and 3999
return num + " is invalid input";
}

for (var i = 3 ; i >= 0 ; i--) { // index through the powers
}
return romanNumeral.join("");
} // convertToRoman()

var testArr = [1, 2, 3, 4, 5, 9, 12, 16, 29, 44, 45, 68, 83, 97, 99, 500, 501, 649,
798, 891, 1000, 1004, 1006, 1023, 2014, 3099, 3479, 3694, 3999, -6, "apple"];

for (var i = 0 ; i < testArr.length ; i++) {
console.log("Converting " + testArr[i] + " ---> " + convertToRoman(testArr[i]));
}
});

It definitely had fewer lines of code than my original but not as small of some of the others I see here - though they hard coded a little and I was interested in what the algorithm would be.

#60

My solution is perhaps lower than intermediate scripting level, but works:

function convertToRoman(num) {

/convert number to a string and split it to an array;
we reverse the array to make possible get subNums by index, coz as input
we have units in any way, and its index (the last without reverse) will be
changed each time by other (previous) subNums;
/
var numArr = num.toString().split("").reverse();

// after reverse the array, get subNums by index;
var units = numArr[0];
var tens = numArr[1];
var hundreds = numArr[2];

// but thousands are all the subnums after hundreds
var thousands = numArr.slice(3).reverse().join("");

// arrays with roman numbers
var romUnitsArr = [‘I’, ‘II’, ‘III’, ‘IV’, ‘V’, ‘VI’, ‘VII’, ‘VIII’, ‘IX’];
var romTensArr = [‘X’, ‘XX’, ‘XXX’, ‘XL’, ‘L’, ‘LX’, ‘LXX’, ‘LXXX’, ‘XC’];
var romHundredsArr = [‘C’, ‘CC’, ‘CCC’, ‘CD’, ‘D’, ‘DC’, ‘DCC’, ‘DCCC’, ‘CM’];
var romans = [];

// get romans
var romUnits = romUnitsArr[units - 1];
var romTens = romTensArr[tens - 1];
var romHundreds = romHundredsArr[hundreds - 1];
var romThousands = "’’;
for (var i=0; i<thousands; i++) {
romThousands += ‘M’;
}

//push all romans into array in correct order
romans.push(romThousands);
romans.push(romHundreds);
romans.push(romTens);
romans.push(romUnits);

// filter out all booleans (delete “”, null)
var romanNumber = romans.filter(Boolean).join("");
return romanNumber;
}
convertToRoman(891);

#61

Can you please help me understand why did you initialize values for accumulator and did not directly use s and calculated variables?

I tried to directly use the variable but I got incorrect answer.

#62

I came up with almost the same!
But is there a significant difference? performance? security?

function convertToRoman(num) {
var roman = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX","V", "IV", "I"],
arabic = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
result = "";

while (num > 0){
for (var i = 0; i < arabic.length; i++){
if (num - arabic[i] >= 0){
result += roman[i];
num -= arabic[i];
break ;
}
}
}
return result;
}

#66

I used if else because I couldn’t think of anything else. Is this too bad??

function convertToRoman(num) {
var original = num;
var arr = num.toString().split("").map(function(t){return parseInt(t);});
var ones = ["","I","II","III","IV","V","VI","VII","VIII","IX"];
var tens = ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"];
var hun  = ["", "C","CC","CCC","CD","D","DC","DCC","DCCC","CM"];
var thou = ["","M"];

if (arr.length === 1) {
arr[0] = ones[arr[0]];
} else if (arr.length === 2){
arr[0] = tens[arr[0]];
arr[1] = ones[arr[1]];
} else if (arr.length === 3) {
arr[0] = hun[arr[0]];
arr[1] = tens[arr[1]];
arr[2] = ones[arr[2]];
} else if (arr.length > 3) {
arr[0] = thou[1].repeat(arr[0]);
arr[1] = hun[arr[1]];
arr[2] = tens[arr[2]];
arr[3] = ones[arr[3]];
}
return arr.join("");
}

convertToRoman(8355);

#67

You should be proud!! It’s shorter and easy to read than most I’ve seen

#68

Yes, it was a tough one. Looks good.

I might have used a switch statement instead of the if-else chain, but that’s more style than function.