Problem statement
Write an algorithm which will return the roman numeral of a provided number.
Example:
roman(5) => V
Solution
First we will need a way to map numbers to a roman numeral.
We can use a simple object for this. The numbers we are mapping will be the most significant numerals and some numbers (such as 4) which are written in the format IV (1 before 5).
Our object will look like this where the key is the numeral and the value is the corresponding number:
const NUMERALS = {
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
}
To determine the amount of numerals to add to our end string we need to find out how many times each number in our object goes into our argument and if needed append it to our roman numeral string.
Lets look at an example using the input number 15:
For the numbers 1000 to 40 in our object they do not go into the number 15 so nothing happens here.
(eg. 15 / 100) = 0
When the loop reaches the value of 10 in our object, we divide 15 by 10 to get 1.5. Therefore the number 10 goes into 15 once
(15 / 10 = 1.5)
, so we append an 'X' to our roman numeral string.We need to then subtract 10 from 15 and continue with the loop, which leaves 5. Now the number being used for calculations with the values in our object is 5.
The next iteration of our object will use the value 9,
5/9 = 0.0...
so that numeral is not appended.When it reaches the next property on the object, the value is 5. So we divide by 5, append 'V' to the string and subtract which leaves 0.
The loop will continue to iterate over the last properties in the object. But there is no further numerals appended.
Writing our algorithm
Step 1:
Declare a blank string variable and write a loop block to iterate over all of the keys in our object:
var str = '';
for (var i of Object.keys(NUMERALS)) {
...
}
Step 2:
Inside our loop we need to divide the number passed in by each numeral value:
var q = Math.floor(number / NUMERALS[i]);
The Math.floor()
function here will ensure the number is rounded down.
Step 3:
As q
is the number of times the numeral value goes into our argument we need to multiply that by the numeral value and subtract from our number. For example, if we're using the numeral value of 10 in our loop from our object and our argument was 35:
var q = Math.floor(35/10) = 3;
number = 35 - (3 * 10) = 5;
So our next statement looks like this:
number -= q * NUMERALS[i];
Step 4:
Finally, we append the roman numeral the number of times the value occurs in our argument, using our example from Step 3, q
is 3 (10 goes into 35, 3 times). So we need to append XXX
to our string.
str += i.repeat(q);
All done!
Our completed function then looks like this. Outside of the for loop, we simply return the whole string to finish:
function roman (number) => {
var str = '';
for (var i of Object.keys(NUMERALS)) {
var q = Math.floor(number / NUMERALS[i]);
number -= q * NUMERALS[i];
str += i.repeat(q);
}
return str;
}
Next steps:
- Make our function more robust by adding type checks so it only allows a number input and adding a condition so it only accepts a positive number.
- Writing a test for this function.
Thanks for reading :)
Top comments (0)