Roman Numeral Converter Challenge


#23

Hi there, here is what I came up with.

function convertToRoman(num) {
var numA = num.toString().split("");

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

if (numA.length == 1) {
    return r1[numA];

} else if (numA.length == 2) {
    //console.log("2 digits: " + numA + " | " + r2[numA[0]]);
    return r2[numA[0]] + r1[numA[1]];

} else if (numA.length == 3) {
    return r3[numA[0]] + r2[numA[1]] + r1[numA[2]];

} else if (numA.length == 4) {
    return r4[numA[0]] + r3[numA[1]] + r2[numA[2]] + r1[numA[3]];
}

}

convertToRoman(36);


#24

function convertToRoman(num) {

//Check for the units 
UnitsRoman = ["I","II","III","IV","V","VI","VII", "VIII", "IX"];
UnitsNorm = ["1","2","3","4","5","6","7", "8", "9"];

TensRoman = ["X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"];
TensNorm = ["10", "20", "30", "40", "50", "60", "70", "80", "90"];

HundredsRoman = ["C", "CC", "CCC", "CD","D", "DC", "DCC", "DCCC", "CM"];
HundredsNorm = ["100", "200", "300", "400","500", "600", "700", "800", "900"];

ThousandRoman = ["M", "MM", "MMM", "","D", "DC", "DCC", "DCCC", "CM"];
ThousandNorm = ["1000", "2000", "3000", "400","500", "600", "700", "800", "900"];


var newNum;

arrNum = num.toString();
arrNum = arrNum.split("");
console.log(arrNum.length);


switch (arrNum.length){
	case 1:
		newNum = UnitsRoman[UnitsNorm.indexOf(arrNum[0])];
		break;
		
	case 2:
		if(arrNum[1] === "0"){
			newNum = TensRoman[UnitsNorm.indexOf(arrNum[0])]
		}else{
			newNum = TensRoman[UnitsNorm.indexOf(arrNum[0])] + UnitsRoman[UnitsNorm.indexOf (arrNum[1])];
		}
		break;
	case 3:
		if(arrNum[2] === "0" && arrNum[1] === "0"){
			newNum = HundredsRoman[UnitsNorm.indexOf(arrNum[0])];
		}
		else if(arrNum[1] === "0"){
			newNum = HundredsRoman[UnitsNorm.indexOf(arrNum[0])] + UnitsRoman[UnitsNorm.indexOf(arrNum[2])];
		}
		else{
			newNum = HundredsRoman[UnitsNorm.indexOf(arrNum[0])] + TensRoman[UnitsNorm.indexOf(arrNum[1])] + UnitsRoman[UnitsNorm.indexOf (arrNum[2])];
			}
		break;
		
	case 4:
		//1       0                    0                    0
		if(arrNum[1] === "0" && arrNum[2] === "0" && arrNum[3] === "0"){
			newNum = ThousandRoman[UnitsNorm.indexOf(arrNum[0])];
		}
		//1            0                    0                   1-9
		else if(arrNum[1] === "0" && arrNum[2] === "0" && arrNum[3] != "0"){
			newNum = ThousandRoman[UnitsNorm.indexOf(arrNum[0])] + UnitsRoman[UnitsNorm.indexOf (arrNum[3])];
		}
		//1            0                    1                   6
		else if(arrNum[1] === "0" && arrNum[2] != "0" && arrNum[3] != "0"){
			newNum = ThousandRoman[UnitsNorm.indexOf(arrNum[0])] + TensRoman[UnitsNorm.indexOf(arrNum[2])] + UnitsRoman[UnitsNorm.indexOf (arrNum[3])] ;
		}
		else{
			newNum = ThousandRoman[UnitsNorm.indexOf(arrNum[0])] + HundredsRoman[UnitsNorm.indexOf(arrNum[1])] + TensRoman[UnitsNorm.indexOf (arrNum[2])] + UnitsRoman[UnitsNorm.indexOf (arrNum[3])];
		}
		break;
}
return newNum;

#26

I like the short solutions that hardcode XC, etc.
I opted to stick with single Roman digits only, so my code is a bit more complicated.

function convertToRoman(num) {
  var roman = "";
  var numbers = [
    [1000, "M"],
    [500,  "D"],
    [100,  "C"],
    [50,   "L"],
    [10,   "X"],
    [5,    "V"],
    [1,    "I"]
  ];
  for(var p = 0; p < numbers.length; p++){
    //check for numbers that don't require subtraction
    var c = Math.floor(num / numbers[p][0]);
    num %= numbers[p][0];
    roman += numbers[p][1].repeat(c);
    //that would be enough for long-form roman numbers...
    //check for subtraction - style numbers
    //only if not at 1 already
    if(numbers[p][0] > 1){
      var d = 1;
      //if next highest roman numeral is half of current one, go to the next
      //because numbers like VX are pointless, VX == V
      if (numbers[p][0]/numbers[p+d][0] == 2) {d=2;}
      if (num >= numbers[p][0]-numbers[p+d][0]){
        num -= numbers[p][0]-numbers[p+d][0];
        roman += numbers[p+d][1]+numbers[p][1];
      }
    }
  }
 return roman;
}

#27

Here is my solution:

function convertToRoman(num) {
var romanStr = "";
var nums = [ 1000, 500, 100, 50, 10, 5, 1 ];
var romans = [ "M", "D", "C", "L", "X", "V", "I"];

		function iterate(divisor,index){
  	  romanStr +=  romans[index].repeat(num/divisor);
  	  num %= divisor;
  	};
  	nums.forEach( iterate );

  	return romanStr
  	  .replace(/DCCCC/,"CM").replace(/CCCC/,"CD")
  	  .replace(/LXXXX/,"XC").replace(/XXXX/,"XL")
  	  .replace(/VIIII/,"IX").replace(/IIII/,"IV");
	}

#28

I know this is not prety but it works..... I have been coding for 80 days and I am still trying to understand how to use filter, map, reduce...

This challenge took me approximately 8 days........ my reasoning is basic and honest approach....... Now that I solved it I will look at other answers...to improve my code...

` function convertToRoman(num) {
num = num.toString();

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

if (num.length == 1) {
return rom1[num];
}
else if (num.length == 2) {
return rom2[num[0]] + rom1[num[1]];
}
else if (num.length == 3) {
return rom3[num[0]] + rom2[num[1]] + rom1[num[2]];
}
else {
return rom4[num[0]] + rom3[num[1]] + rom2[num[2]] + rom1[num[3]];

}

}
convertToRoman(154); `


#29

A bit simplistic, would have liked to have given it more time and put some more smarty logic to work out the numeral.


#30

Without using maths. Not sure if it's smart but it works ^^


#31

Interesting to see how other people went about it. Here's my solution, seems lengthier but makes sense to me:

function convertToRoman(num) {
  
if (num > 0 && num < 4000) {
 num = num.toString().split("");

  var romanConv = {
    0: "_",
    1: "I",
    2: "II",
    3: "III",
    4: "IV",
    5: "V",
    6: "VI",
    7: "VII",
    8: "VIII",
    9: "IX",
    10: "X"};
 
 var i = 0;
  while (i<num.length) {
    num.splice(i, 1, romanConv[num[i]]);
    i++;
  }
  
  var length = parseInt(num.length);
  
  if (num.length > 1)  {num[length-2] = num[length-2].replace(/X/g, 'C');
                        num[length-2] = num[length-2].replace(/V/g, 'L');
                        num[length-2] = num[length-2].replace(/I/g, 'X');}
  if (num.length > 2)  {num[length-3] = num[length-3].replace(/X/g, 'M');
                        num[length-3] = num[length-3].replace(/V/g, 'D');
                        num[length-3] = num[length-3].replace(/I/g, 'C');}
  if (num.length > 3)  {num[length-4] = num[length-4].replace(/I/g, 'M');}
  
  num = num.join("");
  num = num.replace(/_/g, "");
 return num;}
 
 else {return "Number must be between 1 - 3999.";}}
  
  
convertToRoman(20);

#32
function convertToRoman(num) {

  function convDigit(digit, highLet, midLet, lowLet) {
    if(digit == 0) return "";
    else if(midLet === undefined && highLet === undefined) return Array(digit+1).join(lowLet);
    else if(digit > 8) return lowLet+highLet;
    else if (digit > 4) return midLet + Array(digit-4).join(lowLet);
    else if (digit == 4) return lowLet+midLet;
    else return Array(digit+1).join(lowLet);    
  }

  var romanNumerals = ["I", "V", "X", "L", "C", "D", "M"]; // able to add more 2 at a time
  //var romanNumerals = ["I", "V", "X", "L", "C", "D", "M", "(barV)", "(barX)", "(barL)", "(barC)", "(barD)", "(barM)"]; 
  var maxPowOf10 = ((romanNumerals.length-1)/2); 
  var digits = [];

  // iterate from lowest to highest digit
  // the highest digit capable of being represented is allowed to exceed 9
  for (var i=0; i<maxPowOf10; i++) {
    digits.push(num%10);
    num = Math.floor(num/10);
  }
  digits.push(num);

  var romanDigits = [];  
  digits.forEach((el, i) => {
    romanDigits.push(convDigit(el, romanNumerals[i*2+2], romanNumerals[i*2+1], romanNumerals[i*2]));
  });

  return romanDigits.reverse().join(""); 

}

convertToRoman(60000);
//convertToRoman(3999999);

#33

I originally started by using a switch case for each digit but couldn't get it to work, plus it was reaaaally long and repetitive. So I came up with this, and I think it's pretty neat :slight_smile:

function convertToRoman(num) {
var result = "";

var ones =['', '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',];

if (num<10){
num = "000"+num;
}
else if (num<100){
num = "00" + num;
}
else if (num<1000){
num = "0" + num;
}
else {num = num.toString();}

result = thousands[num[0]] + hundreds[num[1]] + tens[num[2]] + ones[num[3]];

return result;
}

convertToRoman(1649);


#34

one simple solution

function convertToRoman(num) {
var rec=num.toString();
var niz=rec.split('');
var kontraNiz=niz.reverse();
var kraj=[];
switch (kontraNiz[0]){

case "1": kraj.unshift("I");
break;
case "2": kraj.unshift("II");
break;
  case "3": kraj.unshift("III");
break;
  case "4": kraj.unshift("IV");
break;
  case "5": kraj.unshift("V");
break;
  case "6": kraj.unshift("VI");
break;
  case "7": kraj.unshift("VII");
break;
  case "8": kraj.unshift("VIII");
break;
  case "9": kraj.unshift("IX");
break;

}
switch (kontraNiz[1]){

case "1": kraj.unshift("X");
break;
case "2": kraj.unshift("XX");
break;
  case "3": kraj.unshift("XXX");
break;
  case "4": kraj.unshift("XL");
break;
  case "5": kraj.unshift("L");
break;
  case "6": kraj.unshift("LX");
break;
  case "7": kraj.unshift("LXX");
break;
  case "8": kraj.unshift("LXXX");
break;
  case "9": kraj.unshift("XC");
break;

}
switch (kontraNiz[2]){
case "0":kraj.unshift("");
break;
case "1": kraj.unshift("C");
break;
case "2": kraj.unshift("CC");
break;
case "3": kraj.unshift("CCC");
break;
case "4": kraj.unshift("CD");
break;
case "5": kraj.unshift("D");
break;
case "6": kraj.unshift("DC");
break;
case "7": kraj.unshift("DCC");
break;
case "8": kraj.unshift("DCCC");
break;
case "9": kraj.unshift("CM");
break;
}
switch (kontraNiz[3]){
case "1": kraj.unshift("M");
break;
case "2": kraj.unshift("MM");
break;
case "3": kraj.unshift("MMM");
break;
}
var resenje=kraj.join('');
return resenje;
}

convertToRoman(1004);


#35

I have really been enjoying these little exercises. I found FCC last night and I have been burning through as many of these as I can. I was interested to see what others did with this challenge and this is my first visit to the forums.

Anyways, here is how I solved this one. Could probably be cleaner if I didn't mind decremented romans numerals, but oh well...

    function convertToRoman(num) {
        var retVal = '';
        var numerals = [
            { arabic: 1000, roman: 'M', decr: 100 },
            { arabic: 500,  roman: 'D', decr: 100 },
            { arabic: 100,  roman: 'C', decr: 10 },
            { arabic: 50,   roman: 'L', decr: 10 },
            { arabic: 10,   roman: 'X', decr: 1 },
            { arabic: 5,    roman: 'V', decr: 1 },
            { arabic: 1,    roman: 'I' }
        ];

        numerals.forEach(x => {
            if (num / x.arabic >= 1) {
                retVal += Array(num / x.arabic >> 0).fill(x.roman).join('');
                num = num % x.arabic;   
            }

            if (x.decr !== null) {
                if (num / (x.arabic - x.decr) >= 1) {
                    retVal += numerals.filter(y => y.arabic === x.decr)[0].roman + x.roman;
                    num = num % (x.arabic - x.decr);
                }
            }
        });

        return retVal;
    }
    
    console.log(convertToRoman(36));

#36

I'm actually a little skeptical about solutions to this problem that involve the use of objects. I can't see all your code, but objects in JavaScript don't have a guaranteed order to their properties and that can mess with object-based solutions.

If your code works, then it works, but I usually recommend a pair of arrays for this problem, one containing numbers, the other associated Roman numerals in the same index position.


#37

[Mod edit: Section deleted; please do not cast aspersions on the intelligence of other posters.]

Here's my solution:

function convertToRoman(num) {
 var roma = [
   ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"],
   ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"],
   ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"],
   ["", "M", "MM", "MMM", "MMMM", "MMMMM"],
     ];
 var val=String(num).split("");
 var res="";
 for (var i=val.length-1, j=0; i>=0; --i, ++j)
   res = roma[j][val[i]] + res;
  
  return res;
}

#38

Difficult challenge for me, and had to look around for some help. I came up with this:

function convertToRoman(num) {  
  var roman = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
  var arabic = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
  
  var result = [];
  
  while (num > 0) {
    arabic.forEach(function(key, i) {
      var times = Math.floor(num / key);
      var remainder = num % key;
      
      result.push(roman[i].repeat(times));
      num = remainder;
    });
  }
  
  return result.join("");
}

#39

Hey all,
Came up with this. I previously put it in an if/else/else/else statement, but this is already a lot better. I saw the solution up with the hardcoding of the edge cases (4 & 9) and it is way more elegant, but it follows the same idea.

function convertToRoman(num) {
  var digits= num.toString(10).split("").map(function(t){return parseInt(t)});
  var romanNumerals = ["I", "V", "X", "L", "C", "D", "M"];
  var totalDigits = digits.length;
  var answer = "";
  
  for (currentDigit = 0; currentDigit<totalDigits; currentDigit++){
    powerOfTen = totalDigits-currentDigit-1; // calculate the power of ten of the current digit x = 0, x0=1, x00=2, x000=3;
    switch (digits[currentDigit]) {
      case 0: break;  // in case of 0, don't add anything to the result
      case 1:
      case 2:
      case 3: // in case of 1,2,3, add x times the right roman numeral.
        answer += romanNumerals[powerOfTen*2].repeat(digits[currentDigit]);
        break;
      case 4: // in case of 4, use one of the numerals and one of the 5x numeral, 1 up in the array.
        answer += (romanNumerals[powerOfTen*2] + romanNumerals[powerOfTen*2 + 1]);
        break;
      case 5: // in case of 5, add the 5x numeral
        answer += romanNumerals[powerOfTen*2+1];
        break;
      case 6:
      case 7: 
      case 8: // 6,7,8, add 5x numeral followed by x-5 times single numeral
        answer += romanNumerals[powerOfTen*2+1] + romanNumerals[powerOfTen*2].repeat(digits[currentDigit]-5);
        break;
      case 9: // 9, add single numeral followed by 10x numeral.
      answer += (romanNumerals[powerOfTen*2] + romanNumerals[powerOfTen*2 + 2]);
    }
  }
   
  return answer;
}

#40

I did something similar, but I used an object instead of dual-arrays:


#41

:disappointed:

function convertToRoman(num) {
  var numArray = num.toString().split(''),
      argLen = num.toString().length,
      onesPlace,
      tensPlace,
      hunsPlace,
      thouPlace,
      answer = "",
      romanNumerals = {
           0: "",
           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"
      };
  
  switch (argLen) {
    case 1:
      onesPlace = romanNumerals[numArray[0]];
      answer = onesPlace;
      break;
    case 2:
      onesPlace = romanNumerals[numArray[1]];
      var x = numArray[0] * 10;
      tensPlace = romanNumerals[x];
      answer = tensPlace.concat(onesPlace);
     break;
    case 3: 
      onesPlace = romanNumerals[numArray[2]]; 
      x = numArray[1] * 10;
      tensPlace = romanNumerals[x];
      var y = numArray[0] * 100;
      hunsPlace = romanNumerals[y];
      answer = hunsPlace.concat(tensPlace, onesPlace);
     break;
    case 4:
      onesPlace = romanNumerals[numArray[3]]; 
      x = numArray[2] * 10;
      tensPlace = romanNumerals[x];
      y = numArray[1] * 100;
      hunsPlace = romanNumerals[y];
      var z = numArray[0] * 1000;
      thouPlace = romanNumerals[z];
      answer = thouPlace.concat(hunsPlace, tensPlace, onesPlace);
     break;
  }   
  
  
 return answer;
}

convertToRoman(3999);

#42

That is some elegant code right there!


#43

Hi,
This is my solution :

function convertToRoman(num) {
 
  var number = num.toString().split('');
 
  var numberUnits  = number.splice(-1);
  var numberTens  = number.splice(-1);
  var numberHundreds  = number.splice(-1);
  var numberThousands = number.splice(-1);
  var result = [];
  
  var units = {1:"I", 2:"II", 3:"III", 4:"IV", 5:"V", 6:"VI", 7:"VII", 8:"VIII", 9:"IX"};
  var tens = {1:"X", 2:"XX", 3:"XXX", 4:"XL", 5:"L", 6:"LX", 7:"LXX", 8:"LXXX", 9:"XC"};
  var hundreds = {1:"C", 2:"CC", 3:"CCC", 4:"CD", 5:"D", 6:"DC", 7:"DCC", 8:"DCCC", 9:"CM"};
  var thousands = {1:"M", 2:"MM", 3:"MMM"}; 
   
  result.push(thousands[numberThousands], hundreds[numberHundreds], tens[numberTens],  units[numberUnits]);

  return result.join('');
}

Cheers and happy coding :slight_smile: