Post your Roman Numeral Converter solutions here! (Fall 2022)

Here is my slow-poke code, done before class where Ramon showed us how to re-factor the code more efficiently:

function convertToRoman(num) {
if (num <= 0) return ‘error’;

let result = ‘’;
let remaining = num;

if (num >= 1000) {
for (let i = 0; i < Math.floor(num / 1000); i++) {
result += ‘M’;
}
remaining = num % 1000;
}

if (remaining >= 900) {
result += ‘CM’;
remaining -= 900;
}

if (remaining >= 500) {
result += ‘D’;
remaining -= 500;
}

if (remaining >= 400) {
result += ‘CD’;
remaining -= 400;
}

if (remaining >= 100) {
for (let i = 0; i < Math.floor(remaining / 100); i++) {
result += ‘C’;
}
remaining = remaining % 100;
}

if (remaining >= 90) {
result += ‘XC’;
remaining -= 90;
}

if (remaining >= 50) {
result += ‘L’;
remaining -= 50;
}

if (remaining >= 40) {
result += ‘XL’;
remaining -= 40;
}

if (remaining >= 10) {
for (let i = 0; i < Math.floor(remaining / 10); i++) {
result += ‘X’;
}
remaining = remaining % 10;
}

if (remaining >= 9) {
result += ‘IX’;
remaining -= 9;
}

if (remaining >= 5) {
result += ‘V’;
remaining -= 5;
}

if (remaining >= 4) {
result += ‘IV’;
remaining -= 4;
}

if (remaining >= 1) {
for (let i = 0; i < remaining; i++) {
result += ‘I’;
}
remaining = 0;
}

if (remaining != 0) return ‘error’;

return result;
}

convertToRoman(36);

console.log(convertToRoman(1798));

3 Likes

Funny, I think your thought process was similar to mine (also done before class) - only that I literally declared thousands of variables :wink:

function convertToRoman(num) {
  //break into biggest chunks and get remainders after each chunk
  //die thousands etc müssen dann noch umgewandelt werden; Achtung: strings können in javascript aber nicht multipliziert werden
  let thousands = Math.floor(num / 1000);
  let remains = num - thousands*1000;
  thousands = "M".repeat(thousands);
  let nineHundreds = Math.floor(remains / 900);
  remains -= nineHundreds*900;
  nineHundreds = "CM".repeat(nineHundreds);
  let fiveHundreds = Math.floor(remains / 500);
  remains -= fiveHundreds*500;
  fiveHundreds = "D".repeat(fiveHundreds);
  let fourHundreds = Math.floor(remains / 400);
  remains -= fourHundreds*400;
  fourHundreds = "CD".repeat(fourHundreds);
  let hundreds = Math.floor(remains / 100);
  remains -= hundreds*100;
  hundreds = "C".repeat(hundreds);
  let nineties = Math.floor(remains / 90);
  remains -= nineties*90;
  nineties = "XC".repeat(nineties);
  let fifties = Math.floor(remains / 50);
  remains -= fifties*50;
  fifties = "L".repeat(fifties);
  let fourties = Math.floor(remains / 40);
  remains -= fourties*40;
  fourties = "XL".repeat(fourties);
  let tens = Math.floor(remains / 10);
  remains -= tens*10;
  tens = "X".repeat(tens);
  let nines = Math.floor(remains / 9);
  remains -= nines*9;
  nines = "IX".repeat(nines);
  let fives = Math.floor(remains / 5);
  remains -= fives*5;
  fives = "V".repeat(fives);
  let fours = Math.floor(remains / 4);
  remains -= fours*4;
  fours = "IV".repeat(fours);
  let ones = Math.floor(remains / 1);
  ones = "I".repeat(ones);

  //add all of them together
  return (thousands + nineHundreds + fiveHundreds + fourHundreds + hundreds + nineties + fifties + fourties + tens + nines + fives + fours + ones);
}

console.log(convertToRoman(36));
3 Likes

That’s great Sandra! Great minds think alike. Are you also doing the Responsive Web Design boot camp, or did you already complete that one previously?

1 Like

I had the same approach, but made one helping function for all :joy:

function convertSingleToRoman(num, einheit) {
  //einheit: 0-9: 10^0, 10-99: 10^1, 101-999: 10^2 1000-3999: 10^3
    const Numerals = {
      0: "",
      1: "I",
      5: "V",
      10: "X",
      50: "L",
      100: "C",
      500: "D",
      1000: "M"
    }
    switch (num) {
      case '0':
        return Numerals[0];;
      case '1':
        return Numerals[einheit];
      case '2':
        return Numerals[einheit] + Numerals[einheit];
      case '3':
        return Numerals[einheit] + Numerals[einheit] + Numerals[einheit];
      case '4':
        return Numerals[einheit] + Numerals[5 * einheit];
      case '5':
        return Numerals[5 * einheit];
      case '6':
        return Numerals[5 * einheit] + Numerals[einheit];
      case '7':
        return Numerals[5 * einheit] + Numerals[einheit] + Numerals[einheit];
      case '8':
        return Numerals[5 * einheit] + Numerals[einheit] + Numerals[einheit] + Numerals[einheit];
      case '9': 
        return Numerals[einheit] + Numerals[10 * einheit];
      default:
        return false;
    }
  }

function convertToRoman(num) {
  let digitArray = num.toString().split("");
  for (let index in digitArray) {
    digitArray[index] = convertSingleToRoman(digitArray[index], Math.pow(10, digitArray.length - 1 - index));
  }
  return digitArray.join("");
}
3 Likes

Yes, I’m also doing the Web Design bootcamp (although I have already done a little bit of HTML and CSS ages ago (pre-HTML5 ;-))

1 Like

function convertToRoman(num) {
//declare lookup variable with object property key/value pairs
let lookup = {
M: 1000,
CM: 900,
D: 500,
CD: 400,
C: 100,
XC: 90,
L: 50,
XL: 40,
X: 10,
V: 5,
IV: 4,
I: 1
},
//declare for loop and while condition; set increment and decrement
romanNum = “”, x;
for (x in lookup) {
while(num >= lookup){
romanNum += x;
num -= lookup;
}
}
//return roman numeral
return romanNum;
}
console.log(convertToRoman(36));

4 Likes

Here is my attempt using the switch case statement and a double array.

function convertToRoman(num) {
  if (num >= 4000 || num <= 0) { 
    return 'Converter is limited to numbers below 4000';
  } else if (/\D/.test(num)) {
    return 'Input includes non digit characters'
  }

  const romanSymbol = [['I','IV','V','IX'],['X','XL','L','XC'],['C','CD','D','CM'],['M']];

  const arrNum = num.toString().match(/\d/g).reverse();
  console.log(arrNum);
  const arrRoman = []; // Declare array to build Roman Number
  for(let i=0; i<arrNum.length; i++){
    switch (arrNum[i]){
      case '0':
        break;
      case '9':
        arrRoman.unshift(romanSymbol[i][3]);
        break;
      case '8':
        arrRoman.unshift(romanSymbol[i][0]);
      case '7':
        arrRoman.unshift(romanSymbol[i][0]);
      case '6':
        arrRoman.unshift(romanSymbol[i][0]);
      case '5':
        arrRoman.unshift(romanSymbol[i][2]);
        break;
      case '4':
        arrRoman.unshift(romanSymbol[i][1]);
        break;
      case '3':
        arrRoman.unshift(romanSymbol[i][0]);
      case '2':
        arrRoman.unshift(romanSymbol[i][0]);
      case '1':
        arrRoman.unshift(romanSymbol[i][0]);
      break;
    }
  }
  return num = arrRoman.join('');
}

console.log(convertToRoman(3948 ))
3 Likes

Here is a shorter version using class, and lookup.

const lookup = {'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}

class NumeralConverter {
  constructor(number){
    this.number = number;
    this.result = '';
  }
  processNumeral(symbol, symbolValue) {
    while (this.number >= symbolValue) {
      this.result += symbol;
      this.number -= symbolValue;
    }
  }
}


function convertToRoman(num) {
  let converter = new NumeralConverter(num);
  for (const roman in lookup) {
    converter.processNumeral(roman, lookup[roman]);
  }
  return converter.result;
}


console.log(convertToRoman(2893));
3 Likes

Here is my solution. Comments are highly welcome.
const convertToRoman = num => {
let lookUpTable= {
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
};
let result = ‘’;
for (const[romanNumeral,arabicNumeral] of Object.entries(lookUpTable)){
while (num >= arabicNumeral){
result += romanNumeral;
num -= arabicNumeral;
}
}
return result;
};

console.log(convertToRoman(83)); // should log LXXXIII

3 Likes

Wooow, there are so many ways to Rom…an Numerals!
This is my solution without having watched the video.

function convertToRoman(num) {
  let romanNum = [];

  while (num != 0) {
    if (num >= 1000) {
      romanNum.push("M");
      num -= 1000;
    } else if (num >= 900){
      romanNum.push("CM");
      num -= 900;
    } else if (num >= 500){
      romanNum.push("D");
      num -= 500;
    } else if (num >= 400){
      romanNum.push("CD");
      num -= 400;
    } else if (num >= 100){
      romanNum.push("C");
      num -= 100;
    } else if (num >= 90){
      romanNum.push("XC");
      num -= 90;
    } else if (num >= 50){
      romanNum.push("L");
      num -= 50;
    } else if (num >= 40){
      romanNum.push("XL");
      num -= 40;
    } else if (num >= 10){
      romanNum.push("X");
      num -= 10;
    } else if (num >= 9){
      romanNum.push("IX");
      num -= 9;
    } else if (num >= 5){
      romanNum.push("V");
      num -= 5;
    } else if (num >= 4){
      romanNum.push("IV");
      num -= 4;
    } else if (num >= 1){
      romanNum.push("I");
      num -= 1;
    } 
  }
  
  romanNum = romanNum.join("");
 return romanNum;
}

convertToRoman(36);
3 Likes

Here is my solution. It’s not the smartest one and not even the shortest but works.

function convertToRoman(num) {

  let thousandsProto;
  let hundredsProto;
  let tensProto;
  let cipherProto;

  let thousands = "";
  let hundreds = "";
  let tens = "";
  let cipher = "";
  let numeralNumber;


  thousandsProto = Math.floor(num / 1000);

  for (let i = 0; i < thousandsProto; i++) {
    thousands += "M";
  }

  // console.log(thousandsProto);
  // console.log(thousands);

  
  hundredsProto = Math.floor((num % 1000) / 100);
  // console.log(hundredsProto);

  switch(hundredsProto) {
    case 1:
      hundreds = "C";
      break;
    case 2:
      hundreds = "CC";
      break;
    case 3:
      hundreds = "CCC";
      break;
    case 4:
      hundreds = "CD";
      break;
    case 5:
      hundreds = "D";
      break;
    case 6:
      hundreds = "DC";
      break;
    case 7:
      hundreds = "DCC";
      break;
    case 8:
      hundreds = "DCCC";
      break;
    case 9:
      hundreds = "CM";
      break;

  }

  // console.log(hundreds);


  tensProto = Math.floor((num % 100) / 10);
  // console.log(tensProto);

  switch(tensProto) {
    case 1:
      tens = "X";
      break;
    case 2:
      tens = "XX";
      break;
    case 3:
      tens = "XXX";
      break;
    case 4:
      tens = "XL";
      break;
    case 5:
      tens = "L";
      break;
    case 6:
      tens = "LX";
      break;
    case 7:
      tens = "LXX";
      break;
    case 8:
      tens = "LXXX";
      break;
    case 9:
      tens = "XC";
      break;

  }

  // console.log(tens);


  cipherProto = Math.floor(num % 10);
  // console.log(cipherProto);

  switch(cipherProto) {
      case 1:
        cipher = "I";
        break;
      case 2:
        cipher = "II";
        break;
      case 3:
        cipher = "III";
        break;
      case 4:
        cipher = "IV";
        break;
      case 5:
        cipher = "V";
        break;
      case 6:
        cipher = "VI";
        break;
      case 7:
        cipher = "VII";
        break;
      case 8:
        cipher = "VIII";
        break;
      case 9:
        cipher = "IX";
        break;

    }

    // console.log(cipher);

    numeralNumber = thousands + hundreds + tens + cipher;
    // console.log(numeralNumber);


  return numeralNumber;

}

console.log(convertToRoman(36));
console.log(convertToRoman(3457));
2 Likes

Here’s my solution. I can now see that many of the other, more efficient solutions are essentially doing the same thing as I’m doing, except instead of the copy-paste of each block in the if-else, the equivalent to the concatenation is implemented once, and objects are created to map the Roman numerals onto their specific values.

In that case, my question is: how does one gain the intuition to simplify the process in these ways? Is it just a matter of time/doing exercises/reading other people’s solutions and learning from them?

function convertToRoman(num) {
 let countDown = num;
 let romanStr = "";
 while (countDown > 0){
   if (countDown >= 1000) {
     romanStr += "M";
     countDown -= 1000;
     continue;
   } else if (countDown >= 900) {
     romanStr += ("CM");
     countDown -= 900;
     continue;
   } else if (countDown >= 500) {
     romanStr += ("D");
     countDown -= 500;
   } else if (countDown >= 400) {
     romanStr += ("CD");
     countDown -= 400;
   } else if (countDown >= 100) {
     romanStr += ("C");
     countDown -= 100;
   } else if (countDown >= 90) {
     romanStr += ("XC");
     countDown -= 90;
   } else if (countDown >= 50) {
     romanStr += ("L");
     countDown -= 50;
   } else if (countDown >= 40) {
     romanStr += ("XL");
     countDown -= 40;
   } else if (countDown >= 10) {
     romanStr += ("X");
     countDown -= 10;
   } else if (countDown >= 9) {
     romanStr += ("IX");
     countDown -= 9;
   } else if (countDown >= 5) {
     romanStr += ("V");
     countDown -= 5;
   } else if (countDown >= 4) {
     romanStr += ("IV");
     countDown -= 4;
   } else if (countDown >= 1) {
     romanStr += ("I");
     countDown -= 1;
   
   }
 }
 
 return romanStr;
}

console.log(convertToRoman(36));
1 Like

After reviewing some of the other solutions, I’ve gone ahead and refactored:

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

 let countDown = num;
 let romanStr = "";
 for (let i = 0; i < conversions.length; i++) {
   while (countDown >= conversions[i][0]) {
     romanStr += conversions[i][1];
     countDown -= conversions[i][0];
   }
 }
 
 return romanStr;
}

console.log(convertToRoman(36));
3 Likes

All the things you mentioned are important. If you only do exercises but don’t look at other people’s solutions, you get better with the tools you already know. But you won’t know the limits of your knowledge.
When you finished an exercise, go and look at other peoples solutions - try to understand what they did and then try to use that way on a similar problem yourself.

Trust me, if you constantly see people using some way you don’t know, you really want to figure out how to do it that way yourself :laughing:

2 Likes

Hi everyone!

I was trying to come with a different solution but… :sweat_smile: :rofl: Too late. :upside_down_face:

I have sent this solution (similar to others I have saw here I am afraid, nothing new under the stars :face_with_monocle:):

function convertToRoman(num) {

  const romansArabics = {
    "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
  };
  let romans = "";
  let arabic = 0;
  // console.log({num, romans, arabic});

  // Loop throw all romans (properties) in romansArabics object
  for (const roman in romansArabics) {

    // Assign the value of the property (roman) to the arabic variable
    arabic = romansArabics[roman];
    // console.log(`Arabic: ${romansArabics[roman]} | Roman ${roman}`);

    // Loops while number minus arabic value is bigger or equal to 0
    while (num - arabic >= 0) {
      // Concat the roman property to romans variable
      romans += roman;
      // Subtract the arabic value to the number, before the new iteration
      num -= arabic;
      // console.log({num, romans, arabic, roman});
    }

  }

  return romans;
}
console.log(convertToRoman(2022));

Great job everyone. You all rocks!!!

2 Likes

Just revisiting some solutions and I do not see anyone mentioning the little optimization you applied by removing the ‘processed’ inner array once handled. Nice! I do like this solution.

2 Likes

This is a very nice approach to solving this solution. I like how you applied recursion and presented the code so compact that it remains easily readable. Nice!

1 Like

My belated solution - I would not have known to use “while” without doing the course or reviewing other people’s answers. I’m not sure of the thought processes people use to decide whether to use switch case, for loops or while - is this something that will just come naturally to me, the more I practice?

Also, when I started doing this solution, I was doing it back to front and wondering why, e.g. (24) would always return “IV”. I also initially missed out many of the + signs before the = in the second lines of the while statements, which gave some interesting results.

function convertToRoman(num) {

let newStr = "";

while (num >= 1000) {
  newStr += "M";
  num -= 1000;
}
while (num >= 900) {
  newStr += "C" + "M";
  num -= 900;
}
while (num >= 600) {
  newStr += "D" + "C";
  num -= 600;
}
while (num >= 500) {
  newStr += "D";
  num -= 500;
}
while (num >= 400) {
  newStr += "C" + "D";
  num -= 400;
}
while (num >= 100) {
  newStr += "C";
  num -= 100;
}
while (num >= 90) {
  newStr += "X" + "C";
  num -= 90;
}
while (num >= 50) {
  newStr += "L";
  num -= 50;
}
while (num >= 40) {
  newStr += "X" + "L";
  num -= 40;
}
while (num >= 39) {
  newStr += "I" + "X" + "L";
  num -= 39;
}
while (num >= 10) {
  newStr += "X";
  num -= 10;
}
while (num >= 9) {
  newStr += "I" + "X";
  num -= 9
}
while (num >= 5) {
  newStr += "V";
  num -= 5;
}
while (num >= 4) {
  newStr += "I" + "V";
  num -= 4;
}
while (num >= 1) {
  newStr += "I";
  num -= 1;
}
return newStr;
}
console.log(convertToRoman(999));
4 Likes

Hi Jane @Jane2963637

No worries, try to solve the problems with your actual knowledge you could back later on and try to solve again.

The most important it is make your code and after you can try to make it more readable, prettier or more efficient. It is normal.

Jane don’t be hard on yourself. Congratulate yourself often after you try or if you succeed, it doesn’t matter. When I’m stuck, after I try I play a song that makes me dance and I start dancing. :joy: :dancer:

You could use Pomodore Technique and play a song after those 25 min of focusing, for example. It is a good technique for learning and working.

Happy coding!! Repeat after me: You rock Jane!! :smile:

P.S. Speaking about rocks… One of my favourites moments… I hope it makes you laugh.

# The Big Bang Theory - Sheldon: “Geology isn’t a real science”

(I am a geologist also :rofl:)

3 Likes

In my revised solution here, I created an array for the Roman numerals and their Arabic counterparts. This way, when I iterated through, I was sure that it would start with the biggest number, and then work its way down to the smallest one, since the array is an ordered structure.

I noticed that some other student solutions used objects instead but iterated through in the same way, such as this one.

I used an array because I thought that the keys would not maintain a strict order in an object, meaning that I couldn’t be sure that it would be testing from largest to smallest value, and that seems to be confirmed in this lesson, which notes: “Objects do not maintain an ordering to stored keys like arrays do; thus a key’s position on an object, or the relative order in which it appears, is irrelevant when referencing or accessing that key.”

So I guess my question is: why is this algorithm working predictably when using objects instead of arrays?

3 Likes