loading...

Roman Numeral Converter

superhackerman profile image Mark Harless ใƒป4 min read

JavaScript Algorithm and Data Structures (2 Part Series)

1) Palindrome Checker 2) Roman Numeral Converter

I'm continuing my quest to complete Free Code Camp's JavaScript Algorithms and Data Structures section. If you are new to coding or need a refresher, I highly suggest Free Code Camp! The lessons are short and sweet, and each of them has a challenge at the end!

It's important to note that I'm going back-and-forth between solving the problem and blogging. So what you're reading here is my thought process along the way. It won't be perfect but it's what I'm thinking.

Moving to the second algorithm:

Convert the given number into a Roman Numeral. All Roman Numeral answers should be provided in the upper-case.

And that's all I need to get started. This one is a bit more difficult than the previous. I don't know how I'm going to do it but I know I should create an object for my Roman Numerals (I think):

function convertToRoman(num) {
 const romanNumerals = {
   1: "I",
   5: "V",
   10: "X",
   50: "L",
   100: "C",
   500: "D",
   1000: "M"
 }
}

I made it a constant because it will never change. The number 10 will always and forever be equal to "X". In my head, I know that formulas never change. Therefore, always make them a constant!

Edit: I'm just now realizing that maybe I don't absolutely need an object as I stated above but I will keep it there anyway. I'm not sure what best practice is in a situation like this.

So, now we have to slowly convert num to a string. Let's create that empty string variable. This will be what we return:

function convertToRoman(num) {
  const romanNumerals = {
    1: "I",
    5: "V",
    10: "X",
    50: "L",
    100: "C",
    500: "D",
    1000: "M"
  }

  // return value
  let romanNumeral = ""
}

My thought process now is to subtract from num one-by-one and add the corresponding Roman Numeral to romanNumeral. For instance, the number 1,500 will be subtracted by 1,000. At the same time, "M" will be added to our return statement. Then 500 will be subtracted from num, and "D" will be added to our return statement. This will spit out "MD" as the Roman Numeral.

I think this can best be achieved with a while loop with if statements nested inside. It will start with 1,000 and go down (or up if you're looking at our romanNumerals object).

Note: In case it's been a while since you've used Roman Numerals, Roman Numerals can be grouped with up to three characters. This means "III" works but "IIII" doesn't (it's "IV"). This same rule applies to the bigger numbers. "XXX" is 30 but "XXXX" is not 40 ("XL")

function convertToRoman(num) {
  const romanNumerals = {
    1: "I",
    5: "V",
    10: "X",
    50: "L",
    100: "C",
    500: "D",
   1000: "M"
  }

  // return value
  let romanNumeral = ""

  while (num !== 0) {
    if (num >= 1000) {
      romanNumeral += romanNumerals[1000]
      num -= 1000
    }
  }

  return romanNumeral
}

convertToRoman(2000);
// "MM"

We got our function to return the correct Roman Numeral conversion for 2000. Great! Let's keep this going!

function convertToRoman(num) {
  const romanNumerals = {
    1: "I",
    5: "V",
    10: "X",
    50: "L",
    100: "C",
    500: "D",
   1000: "M"
  }

  // return value
  let romanNumeral = ""

  while (num !== 0) {
    if (num >= 1000) {
      romanNumeral += romanNumerals[1000]
      num -= 1000
    } else if (num >= 500) {
        romanNumeral += romanNumerals[500]
        num -= 500
    } else if (num >= 400) {
        romanNumeral += "CD"
        num -= 400
    }  
  }

  return romanNumeral
}

I'm already seeing a downfall to how we use the romanNumerals object. We can, of course, apply template literals but that's just going to make our code longer and unreadable so I've decided to remove it. I do apologize that this will be a case of draw the rest of the owl but I don't want to be typing forever!

function convertToRoman(num) {
  let romanNumeral = ""

  while (num !== 0) {
    if (num >= 1000) {
      romanNumeral += "M"
      num -= 1000
    } else if (num >= 500) {
        romanNumeral += "D"
        num -= 500
    } else if (num >= 400) {
        romanNumeral += "CD"
        num -= 400
    } else if (num >= 100) {
        romanNumeral += "C"
        num -= 100
    } else if (num >= 90) {
        romanNumeral += "XC"
        num -= 90
    } else if (num >= 50) {
        romanNumeral += "L"
        num -= 50
    } else if (num >= 40) {
        romanNumeral += "XL"
        num -= 40
    } else if (num >= 10) {
        romanNumeral += "X"
        num -= 10
    } else if (num >= 9) {
        romanNumeral += "IX"
        num -= 9
    } else if (num >= 5) {
        romanNumeral += "V"
        num -= 5
    } else if (num >= 4) {
        romanNumeral += "IV"
        num -= 4
    } else if (num >= 1) {
        romanNumeral += "I"
        num -= 1
    }
  }

  return romanNumeral
}

Strangely enough, this returns the correct Roman Numeral for every test except one ๐Ÿคจ. convertToRoman(3999) should return "MMMCMXCIX" but instead, it's returning "MMMDCDXCIX". This is because I have 900 returning "DCD" not "CM". This is an interesting scenario because I've always thought you can group up to 3 letters together but apparently this is a special case. It does make sense though. This is an easy fix. We just insert another if else statement immediately after the first if statement:

if (num >= 1000) {
      romanNumeral += "M"
      num -= 1000
    } else if (num >= 900) {
        romanNumeral += "CM"
        num -= 900
    }

Ta-da! This passes all of our tests! Our final result is below. I'm sure there are simpler ways to complete this challenge but that's what refactoring is for. Thank you for reading!

function convertToRoman(num) {
  let romanNumeral = ""

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

  return romanNumeral
}

JavaScript Algorithm and Data Structures (2 Part Series)

1) Palindrome Checker 2) Roman Numeral Converter

Posted on by:

superhackerman profile

Mark Harless

@superhackerman

A recent graduate of software engineering immersive boot camp eager to apply creative and freelance skills into the tech industry.

Discussion

markdown guide