Roman Numeral Converter
Tags: javascript, algorithms
Published: 2020-07-12 17:16:14

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

```js
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`:

```js
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")

```js
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! 

```js
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](https://i.kym-cdn.com/photos/images/newsfeed/000/572/078/d6d.jpg) but I don't want to be typing forever!

```js
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:

```js
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!

```js
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
}
```