How can I convert integers into roman numerals?
function romanNumeralGenerator (int) {
}
For example, see the following sample inputs and outputs:
1 = "I"
5 = "V"
10 = "X"
20 = "XX"
3999 = "MMMCMXCIX"
Caveat: Only support numbers between 1 and 3999
This question is related to
javascript
roman-numerals
function convertToRoman (num) {
var v = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
var r = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
var s = "";
for(i = 0; i < v.length; i++) {
value = parseInt(num/v[i]);
for(j = 0; j < value; j++) {
s += r[i];
}
num = num%v[i];
}
return s;
}
This function works on the the different character sets in each digit. To add another digit add the roman numeral string the 1 place, 5 place and next 1 place. This is nice because you update it with only knowing the next set of characters used.
function toRoman(n){_x000D_
var d=0,o="",v,k="IVXLCDM".split("");_x000D_
_x000D_
while(n!=0){_x000D_
v=n%10,x=k[d],y=k[d+1],z=k[d+2];_x000D_
o=["",x,x+x,x+x+x,x+y,y,y+x,y+x+x,y+x+x+x,x+z][v]+o;_x000D_
n=(n-v)/10,d+=2;_x000D_
}_x000D_
_x000D_
return o_x000D_
}_x000D_
_x000D_
var out = "";_x000D_
_x000D_
for (var i = 0; i < 100; i++) {_x000D_
out += toRoman(i) + "\n";_x000D_
}_x000D_
_x000D_
document.getElementById("output").innerHTML = out;
_x000D_
<pre id="output"></pre>
_x000D_
I really liked the solution by jaggedsoft but I couldn't reply because my rep is TOO LOW :( :(
I broke it down to explain it a little bit for those that don't understand it. Hopefully it helps someone.
function convertToRoman(num) {
var 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},roman = '',i;
for ( i in lookup ) {
while ( num >= lookup[i] ) { //while input is BIGGGER than lookup #..1000, 900, 500, etc.
roman += i; //roman is set to whatever i is (M, CM, D, CD...)
num -= lookup[i]; //takes away the first num it hits that is less than the input
//in this case, it found X:10, added X to roman, then took away 10 from input
//input lowered to 26, X added to roman, repeats and chips away at input number
//repeats until num gets down to 0. This triggers 'while' loop to stop.
}
}
return roman;
}
console.log(convertToRoman(36));
In this code, upper limit of numbers can be extended by adding new letters to letterTable:
letterTable = {
0:{
1:'I',
5:'V',
10:'X'
},
1:{
1:'X',
5:'L',
10:'C'
},
2:{
1:'C',
5:'D',
10:'M'
},
3:{
1:'M',
5:'V', // There should be a dash over this letter
10:'X' // There should be a dash over this letter
},
// you can add new level of letters here
};
function romanLetter(i, j){
romanTable = {
'0':'',
'1':letterTable[i][1],
'2':letterTable[i][1]+letterTable[i][1],
'3':letterTable[i][1]+letterTable[i][1]+letterTable[i][1],
'4':letterTable[i][1]+letterTable[i][5],
'5':letterTable[i][5],
'6':letterTable[i][5]+letterTable[i][1],
'7':letterTable[i][5]+letterTable[i][1]+letterTable[i][1],
'8':letterTable[i][5]+letterTable[i][1]+letterTable[i][1]+letterTable[i][1],
'9':letterTable[i][1]+letterTable[i][10]
};
return romanTable[j];
}
function convertToRoman(num) {
numStr = String(num);
var result = '';
var level = 0;
for (var i=numStr.length-1; i>-1; i--){
result = romanLetter(level, numStr[i]) + result;
level++;
}
return result;
}
Well, it seems as I'm not the only one that got stuck on this challenge at FreeCodeCamp. But I would like to share my code with you anyhow. It's quite performant, almost 10% faster than the top-voted solution here (I haven't tested all the others and I guess mine is not the fastest). But I think it's clean and easy to understand:
function convertToRoman(num) {
// Some error checking first
if (+num > 9999) {
console.error('Error (fn convertToRoman(num)): Can\'t convert numbers greater than 9999. You provided: ' + num);
return false;
}
if (!+num) {
console.error('Error (fn convertToRoman(num)): \'num\' must be a number or number in a string. You provided: ' + num);
return false;
}
// Convert the number into
// an array of the numbers
var arr = String(+num).split('').map((el) => +el );
// Keys to the roman numbers
var keys = {
1: ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
2: ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
3: ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'],
4: ['', 'M', 'MM', 'MMM', 'MMMM', 'MMMMM', 'MMMMMM', 'MMMMMMM', 'MMMMMMMM', 'MMMMMMMMM'],
};
// Variables to help building the roman string
var i = arr.length;
var roman = '';
// Iterate over each number in the array and
// build the string with the corresponding
// roman numeral
arr.forEach(function (el) {
roman += keys[i][el];
i--;
});
// Return the string
return roman;
}
It might seem like a limitation that it only can convert numbers up to 9 999. But the fact is that from 10 000 and above a line should be provided above the literals. And that I have not solved yet.
Hope this will help you.
IF this number in HTMLElement (such as span), we recommend to Add HTML attribute data-format
:
<p>Phase <span data-format="roman">4 </span> Sales</p>
Note : This is not a html standard. Javascript code used is visible once you scroll down in the html section on jsfiddle.
Here is the solution with recursion, that looks simple:
const toRoman = (num, result = '') => {
const map = {
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,
};
for (const key in map) {
if (num >= map[key]) {
if (num !== 0) {
return toRoman(num - map[key], result + key);
}
}
}
return result;
};
console.log(toRoman(402)); // CDII
console.log(toRoman(3000)); // MMM
console.log(toRoman(93)); // XCIII
console.log(toRoman(4)); // IV
_x000D_
There is a nice one here on this blog I found using google:
http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter
function romanize (num) {
if (isNaN(num))
return NaN;
var digits = String(+num).split(""),
key = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM",
"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC",
"","I","II","III","IV","V","VI","VII","VIII","IX"],
roman = "",
i = 3;
while (i--)
roman = (key[+digits.pop() + (i * 10)] || "") + roman;
return Array(+digits.join("") + 1).join("M") + roman;
}
I know this is an old question but I'm pretty proud of this solution :) It only handles numbers less than 1000 but could easily be expanded to include however large you'd need by adding on to the 'numeralCodes' 2D array.
var numeralCodes = [["","I","II","III","IV","V","VI","VII","VIII","IX"], // Ones_x000D_
["","X","XX","XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"], // Tens_x000D_
["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"]]; // Hundreds_x000D_
_x000D_
function convert(num) {_x000D_
var numeral = "";_x000D_
var digits = num.toString().split('').reverse();_x000D_
for (var i=0; i < digits.length; i++){_x000D_
numeral = numeralCodes[i][parseInt(digits[i])] + numeral;_x000D_
}_x000D_
return numeral; _x000D_
}
_x000D_
<input id="text-input" type="text">_x000D_
<button id="convert-button" onClick="var n = parseInt(document.getElementById('text-input').value);document.getElementById('text-output').value = convert(n);">Convert!</button>_x000D_
<input id="text-output" style="display:block" type="text">
_x000D_
Here's a way of doing it without having to loop through all the different roman numerals and their corresponding numbers. It has a constant time O(1)
lookup, saving a little in time complexity.
It breaks down each integer from right to left, so 2,473 becomes 3 + 70 + 400 + 2,000
, and then finds the corresponding roman numeral using the romanNumerals hash table, and appends it to the result string. It does this by adding an additional 0
to each integer before the lookup as you move right to left. This solution only works for numbers between 1 and 3,999.
function integerToRoman(int) {
if (int < 1 || int > 3999) {
return -1;
}
var result = '';
var intStr = int.toString();
var romanNumerals = { 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'};
var digit = '';
for (var i = intStr.length - 1; i >= 0; i-- ) {
if (intStr[i] === '0') {
digit += '0';
continue;
}
var num = intStr[i] + digit;
result = romanNumerals[num] + result;
digit += '0';
}
return result;
}
function romanize(num) {
var 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},roman = '',i;
for ( i in lookup ) {
while ( num >= lookup[i] ) {
roman += i;
num -= lookup[i];
}
}
return roman;
}
Reposted from a 2008 comment located at: http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter
just connecting on the answer of Piotr Berebecki. I edited it so that the recursive function does not only subtract 1 from the given number, but it immediately subtracts the highest matched number in the provided array to speed up the process.
// the arrays
var arabicFormat = [1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000];
var romanFormat = ['I', 'IV', 'V', 'IX', 'X', 'XL', 'L', 'XC', 'C', 'CD', 'D', 'CM', 'M'];
function convertToRoman(num) {
// the recursion will stop here returning a blank
if (num === 0){
return '';
}
var returnValue = [];
// this is the main For loop of the function
for (var i=0; i < arabicFormat.length; i++){
if (num >= arabicFormat[i]){
// empty the array on every iteration until it gets to the final number
returnValue = [];
// store the current highest matched number in the array
returnValue.push(romanFormat[i]);
}
}
// get the correct resulting format
returnValue = returnValue.join();
// get the highest matched number value
var whatIndex = romanFormat.indexOf(returnValue);
var substractValue = arabicFormat[whatIndex];
// here the recursion happens
return returnValue + convertToRoman(num - substractValue);
}
I didn't see this posted already so here's an interesting solution using only string manipulation:
var numbers = [1, 4, 5, 7, 9, 14, 15, 19, 20, 44, 50, 94, 100, 444, 500, 659, 999, 1000, 1024];_x000D_
var romanNumeralGenerator = function (number) {_x000D_
return 'I'_x000D_
.repeat(number)_x000D_
.replace(/I{5}/g, 'V')_x000D_
.replace(/V{2}/g, 'X')_x000D_
.replace(/X{5}/g, 'L')_x000D_
.replace(/L{2}/g, 'C')_x000D_
.replace(/C{5}/g, 'D')_x000D_
.replace(/D{2}/g, 'M')_x000D_
.replace(/DC{4}/g, 'CM')_x000D_
.replace(/C{4}/g, 'CD')_x000D_
.replace(/LX{4}/g, 'XC')_x000D_
.replace(/X{4}/g, 'XL')_x000D_
.replace(/VI{4}/g, 'IX')_x000D_
.replace(/I{4}/g, 'IV')_x000D_
};_x000D_
_x000D_
console.log(numbers.map(romanNumeralGenerator))
_x000D_
Use this code:
function convertNumToRoman(num){
const romanLookUp = {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 = ''
// Sort the object values to get them to descending order
Object.keys(romanLookUp).sort((a,b)=>romanLookUp[b]-romanLookUp[a]).forEach((key)=>{
while(num>=romanLookUp[key]){
result+=key;
num-=romanLookUp[key]
}
})
return result;
}
I tried to do this by mapping an array of the arabic numerals to an array of pairs of roman. The nasty 3-level ternaries could be replaced by if() {} else{} blocks to make it more readable. It works from 1 to 3999 but could be extended:
function romanize(num) {
if(num > 3999 || num < 1) return 'outside range!';
const roman = [ ['M', ''], [ 'C', 'D' ], [ 'X', 'L' ], [ 'I', 'V' ] ];
const arabic = num.toString().padStart(4, '0').split('');
return arabic.map((e, i) => {
return (
e < 9 ? roman[i][1].repeat(Math.floor(e / 5)) : ''
) + (
e % 5 < 4
? roman[i][0].repeat(Math.floor(e % 5))
: e % 5 === 4 && Math.floor(e / 5) === 0
? roman[i][0] + roman[i][1]
: Math.floor(e / 5) === 1
? roman[i][0] + roman[i - 1][0]
: ''
);
}).join('');
}
There is several ways to accomplish this. I personally prefer using objects and iterate through the key-value pairs:
const solution=(n)=>{
const romanLetters ={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 romanNumber ='';
let valuesArr = Object.values(romanLetters);
for(let i in valuesArr){
while (n - valuesArr[i] >= 0){
romanNumber+=Object.keys(romanLetters)[i];
n-=valuesArr[i];
}
}
return romanNumber;
}
I personally think the neatest way (not by any means the fastest) is with recursion.
function convert(num) {
if(num < 1){ return "";}
if(num >= 40){ return "XL" + convert(num - 40);}
if(num >= 10){ return "X" + convert(num - 10);}
if(num >= 9){ return "IX" + convert(num - 9);}
if(num >= 5){ return "V" + convert(num - 5);}
if(num >= 4){ return "IV" + convert(num - 4);}
if(num >= 1){ return "I" + convert(num - 1);}
}
console.log(convert(39));
//Output: XXXIX
This will only support numbers 1-40, but it can easily be extended by following the pattern.
JavaScript
function romanize (num) {
if (!+num)
return false;
var digits = String(+num).split(""),
key = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM",
"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC",
"","I","II","III","IV","V","VI","VII","VIII","IX"],
roman = "",
i = 3;
while (i--)
roman = (key[+digits.pop() + (i * 10)] || "") + roman;
return Array(+digits.join("") + 1).join("M") + roman;
}
many other suggestions can be found at http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter
If it is just for display purpose, use the standard HTML with a bit of JS for the value (if needed) and CSS to make it inline:
ol.roman-lowercase,_x000D_
ol.roman-uppercase {_x000D_
display: inline-flex;_x000D_
margin: 0;_x000D_
padding: 0;_x000D_
}_x000D_
_x000D_
ol.roman-lowercase {_x000D_
list-style: lower-roman inside;_x000D_
}_x000D_
_x000D_
ol.roman-uppercase {_x000D_
list-style: upper-roman inside;_x000D_
}
_x000D_
<ol class="roman-lowercase"><li value="4"></li></ol> <!-- iv. -->_x000D_
<ol class="roman-uppercase"><li value="142"></li></ol> <!-- CXLII. -->
_x000D_
function toRoman(n) {
var decimals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
var roman = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
for (var i = 0; i < decimals.length; i++) {
if(n < 1)
return "";
if(n >= decimals[i]) {
return roman[i] + toRoman(n - decimals[i]);
}
}
}
function convertToRoman(num) {
var roNumerals = {
M: Math.floor(num / 1000),
CM: Math.floor(num % 1000 / 900),
D: Math.floor(num % 1000 % 900 / 500),
CD: Math.floor(num % 1000 % 900 % 500 / 400),
C: Math.floor(num % 1000 % 900 % 500 % 400 / 100),
XC: Math.floor(num % 1000 % 900 % 500 % 400 % 100 / 90),
L: Math.floor(num % 1000 % 900 % 500 % 400 % 100 % 90 / 50),
XL: Math.floor(num % 1000 % 900 % 500 % 400 % 100 % 90 % 50 / 40),
X: Math.floor(num % 1000 % 900 % 500 % 400 % 100 % 90 % 50 % 40 / 10),
IX: Math.floor(num % 1000 % 900 % 500 % 400 % 100 % 90 % 50 % 40 % 10 / 9),
V: Math.floor(num % 1000 % 900 % 500 % 400 % 100 % 90 % 50 % 40 % 10 % 9 / 5),
IV: Math.floor(num % 1000 % 900 % 500 % 400 % 100 % 90 % 50 % 40 % 10 % 9 % 5 / 4),
I: Math.floor(num % 1000 % 900 % 500 % 400 % 100 % 90 % 50 % 40 % 10 % 9 % 5 % 4 / 1)
};
var roNuStr = "";
for (var prop in roNumerals) {
for (i = 0; i < roNumerals[prop]; i++) {
roNuStr += prop;
}
}
return roNuStr;
}
convertToRoman(9);
Here is my "as functional as it gets" solution.
var numerals = ["I","V","X","L","C","D","M"],_x000D_
number = 1453,_x000D_
digits = Array(~~(Math.log10(number)+1)).fill(number).map((n,i) => Math.trunc(n%Math.pow(10,i+1)/Math.pow(10,i))), // <- [3,5,4,1]_x000D_
result = digits.reduce((p,c,i) => (c === 0 ? ""_x000D_
: c < 4 ? numerals[2*i].repeat(c)_x000D_
: c === 4 ? numerals[2*i] + numerals[2*i+1]_x000D_
: c < 9 ? numerals[2*i+1] + numerals[2*i].repeat(c-5)_x000D_
: numerals[2*i] + numerals[2*i+2]) + p,"");_x000D_
console.log(result);
_x000D_
I hate listing every possibility into an array ( which many people chose to solve this puzzle) so I use another function to do that work. Here are my solution:
//a function that convert a single number to roman number, you can choose how to convert it so later you can apply to different part of the number_x000D_
function romannum(num,rnum1,rnum2,rnum3){_x000D_
var result = "";_x000D_
if(num >= 1 && num < 4){_x000D_
while(num>0){_x000D_
result += rnum1;_x000D_
num--;_x000D_
}_x000D_
}_x000D_
else if(num > 5 && num < 9){_x000D_
result = rnum2;_x000D_
while(num>5){_x000D_
result += rnum1;_x000D_
num--;_x000D_
} _x000D_
}_x000D_
else if(num == 4){_x000D_
result += rnum1 + rnum2;_x000D_
}_x000D_
else if( num == 5){_x000D_
result += rnum2;_x000D_
}_x000D_
else if( num == 9){_x000D_
result += rnum1+ rnum3;_x000D_
}_x000D_
return result;_x000D_
}_x000D_
//the main function_x000D_
function convertToRoman(num) {_x000D_
num = num.toString().split('');_x000D_
var length = num.length;_x000D_
var x = 0;_x000D_
var result =[];_x000D_
_x000D_
while((length - x) > 0){_x000D_
if(length -x === 4){_x000D_
result.push(romannum(num[x],"M","",""));_x000D_
}_x000D_
else if(length -x === 3){_x000D_
result.push(romannum(num[x],"C","D","M"));_x000D_
}_x000D_
else if(length - x === 2){_x000D_
result.push(romannum(num[x],"X","L","C"));_x000D_
}_x000D_
else if(length - x === 1){_x000D_
result.push(romannum(num[x],"I","V","X"));_x000D_
}_x000D_
x++; _x000D_
}
_x000D_
function toRoman(n) {
var r = '';
for (var c = 0; c < n.length; c++)
r += calcDigit(eval(n.charAt(c)), n.length - c - 1);
return r
}
function Level(i, v, x) {
this.i = i;
this.v = v;
this.x = x
}
levels = [];
levels[0] = new Level('I','V','X');
levels[1] = new Level('X','L','C');
levels[2] = new Level('C','D','M');
function calcDigit(d, l) {
if (l > 2) {
var str = '';
for (var m = 1; m <= d * Math.pow(10, l - 3); m++)
str += 'M';
return str
} else if (d == 1)
return levels[l].i;
else if (d == 2)
return levels[l].i + levels[l].i;
else if (d == 3)
return levels[l].i + levels[l].i + levels[l].i;
else if (d == 4)
return levels[l].i + levels[l].v;
else if (d == 5)
return levels[l].v;
else if (d == 6)
return levels[l].v + levels[l].i;
else if (d == 7)
return levels[l].v + levels[l].i + levels[l].i;
else if (d == 8)
return levels[l].v + levels[l].i + levels[l].i + levels[l].i;
else if (d == 9)
return levels[l].i + levels[l].x;
else
return ''
}
function convertToRoman(num) {
var romNumerals = [["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]];
var runningTotal = 0;
var roman = "";
for (var i = 0; i < romNumerals.length; i++) {
while (runningTotal + romNumerals[i][1] <= num) {
runningTotal += romNumerals[i][1];
roman += romNumerals[i][0];
}
}
return roman;
}
Loops may be more elegant but I find them hard to read. Came up with a more or less hard coded version that's easy on the eyes. As long as you understand the very first line, the rest is a no-brainer.
function romanNumeralGenerator (int) {
let roman = '';
roman += 'M'.repeat(int / 1000); int %= 1000;
roman += 'CM'.repeat(int / 900); int %= 900;
roman += 'D'.repeat(int / 500); int %= 500;
roman += 'CD'.repeat(int / 400); int %= 400;
roman += 'C'.repeat(int / 100); int %= 100;
roman += 'XC'.repeat(int / 90); int %= 90;
roman += 'L'.repeat(int / 50); int %= 50;
roman += 'XL'.repeat(int / 40); int %= 40;
roman += 'X'.repeat(int / 10); int %= 10;
roman += 'IX'.repeat(int / 9); int %= 9;
roman += 'V'.repeat(int / 5); int %= 5;
roman += 'IV'.repeat(int / 4); int %= 4;
roman += 'I'.repeat(int);
return roman;
}
const romanize = num => {_x000D_
const romans = {_x000D_
M:1000,_x000D_
CM:900,_x000D_
D:500,_x000D_
CD:400,_x000D_
C:100,_x000D_
XC:90,_x000D_
L:50,_x000D_
XL:40,_x000D_
X:10,_x000D_
IX:9,_x000D_
V:5,_x000D_
IV:4,_x000D_
I:1_x000D_
};_x000D_
_x000D_
let roman = '';_x000D_
_x000D_
for (let key in romans) {_x000D_
const times = Math.trunc(num / romans[key]);_x000D_
roman += key.repeat(times);_x000D_
num -= romans[key] * times;_x000D_
}_x000D_
_x000D_
return roman;_x000D_
}_x000D_
_x000D_
console.log(_x000D_
romanize(38)_x000D_
)
_x000D_
I feel my solution is much more readable and easy to understand.
var intToRoman = function(num) {
let symbolMap = ['I','V','X','L','C','D','M','P','Q'];
if (num < 1 || num > 9999) {
return null;
}
let i = 0;
let result = '';
while (num) {
let digit = num % 10;
num = parseInt(num / 10);
switch (digit) {
case 1: result = symbolMap[i] + result;
break;
case 2: result = symbolMap[i] + symbolMap[i] + result;
break;
case 3: result = symbolMap[i] + symbolMap[i] + symbolMap[i] + result;
break;
case 4: result = symbolMap[i] + symbolMap[i+1] + result;
break;
case 5: result = symbolMap[i+1] + result;
break;
case 6: result = symbolMap[i+1] + symbolMap[i] + result;
break;
case 7: result = symbolMap[i+1] + symbolMap[i] + symbolMap[i] + result;
break;
case 8: result = symbolMap[i+1] + symbolMap[i] + symbolMap[i] + symbolMap[i] + result;
break;
case 9: result = symbolMap[i] + symbolMap[i+2] + result;
break;
}
i += 2;
}
return result;
};
const basicRomanNumeral = _x000D_
['',_x000D_
'I','II','III','IV','V','VI','VII','VIII','IX','',_x000D_
'X','XX','XXX','XL','L','LX','LXX','LXXX','XC','',_x000D_
'C','CC','CCC','CD','D','DC','DCC','DCCC','CM','',_x000D_
'M','MM','MMM'_x000D_
];_x000D_
_x000D_
function convertToRoman(num) {_x000D_
const numArray = num.toString().split('');_x000D_
const base = numArray.length;_x000D_
let count = base-1;_x000D_
const convertedRoman = numArray.reduce((roman, digit) => {_x000D_
const digitRoman = basicRomanNumeral[+digit + count*10];_x000D_
const result = roman + digitRoman;_x000D_
count -= 1;_x000D_
return result;_x000D_
},'');_x000D_
return convertedRoman;_x000D_
}
_x000D_
function convertToRoman(num) {
var roman = {
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
}
var result = '';
for (var key in roman) {
if (num == roman[key]) {
return result +=key;
}
var check = num > roman[key];
if(check) {
result = result + key.repeat(parseInt(num/roman[key]));
num = num%roman[key];
}
}
return result;
}
console.log(convertToRoman(36));
This is my solution with a single loop
function convertToRoman(num) {
var roman = {
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
};
var romanNum = "";
for(key in roman){
var check = num>=roman[key];
if(check){
console.log(romanNum);
romanNum += key;
num-= roman[key];
}
}
return romanNum
}
convertToRoman(150);
Here's my solution:
var roman = "MX";
function solution(roman) {
var val = 0;
for (let i = 0; i < roman.length; i++) {
if (roman.charAt(i) == 'I') {
if (roman.charAt(i + 1) == 'V') {
val += 4; // IV
} else if (roman.charAt(i + 1) == 'X') {
val += 9; // IX
} else {
val += 1; // I
}
} else if (roman.charAt(i) == 'V') {
if (roman.charAt(i - 1) == 'I') {
val = val;
} else {
val += 5; // V
}
} else if (roman.charAt(i) == 'X') {
if (roman.charAt(i - 1) == 'I') { // Check if there is I before X
val = val;
}else if (roman.charAt(i + 1) == 'L') {
val += 40; // XL
} else if (roman.charAt(i + 1) == 'C') {
val += 90; // XC
} else {
val += 10; // X
}
} else if (roman.charAt(i) == 'L') {
if (roman.charAt(i - 1) == 'X') { // Check if there is X before L
val = val;
} else {
val += 50; // L
}
} else if (roman.charAt(i) == 'C') {
if (roman.charAt(i - 1) == 'X') {
val = val; // XC
}else if (roman.charAt(i + 1) == 'D') {
val += 400; // CD
} else if (roman.charAt(i + 1) == 'M') {
val += 900; // CM
} else {
val += 100; // C
}
} else if (roman.charAt(i) == 'D') {
if (roman.charAt(i - 1) == 'C') {
val = val; // CD
} else {
val += 500; // D
}
} else if (roman.charAt(i) == 'M') {
if (roman.charAt(i - 1) == 'C') {
val = val; // CM
} else {
val += 1000; // M
}
}
}
return val;
}
console.log(solution(roman)); // The answer is: 1010
I wrote this from scratch for freecodecamp challenge. I hope this will help someone.
function convertToRoman(num) {_x000D_
_x000D_
var nums = [0, 0, 0, 0];_x000D_
_x000D_
var numsRom = ["", "", "", ""];_x000D_
_x000D_
var nRom = {_x000D_
I: "I",_x000D_
V: "V",_x000D_
X: "X",_x000D_
L: "L",_x000D_
C: "C",_x000D_
D: "D",_x000D_
M: "M"_x000D_
};_x000D_
/*_x000D_
1,_x000D_
5,_x000D_
10,_x000D_
50,_x000D_
100,_x000D_
500,_x000D_
1000_x000D_
*/_x000D_
_x000D_
var i;_x000D_
_x000D_
nums[0] = Math.floor(num / 1000);_x000D_
nums[1] = Math.floor((num - nums[0] * 1000) / 100);_x000D_
nums[2] = Math.floor((num - nums[0] * 1000 - nums[1] * 100) / 10);_x000D_
nums[3] = num - nums[0] * 1000 - nums[1] * 100 - nums[2] * 10;_x000D_
_x000D_
//1000_x000D_
for (i = 0; i < nums[0]; i++) {_x000D_
numsRom[0] += nRom.M;_x000D_
}_x000D_
_x000D_
//100_x000D_
switch (nums[1]) {_x000D_
case 1:_x000D_
case 2:_x000D_
case 3:_x000D_
for (i = 0; i < nums[1]; i++) {_x000D_
numsRom[1] += nRom.C;_x000D_
}_x000D_
break;_x000D_
case 4:_x000D_
numsRom[1] += nRom.C + nRom.D;_x000D_
break;_x000D_
case 5:_x000D_
numsRom[1] += nRom.D;_x000D_
break;_x000D_
case 6:_x000D_
case 7:_x000D_
case 8:_x000D_
numsRom[1] += nRom.D;_x000D_
for (i = 0; i < nums[1] - 5; i++) {_x000D_
numsRom[1] += nRom.C;_x000D_
}_x000D_
break;_x000D_
case 9:_x000D_
numsRom[1] += nRom.C + nRom.M;_x000D_
}_x000D_
_x000D_
//10_x000D_
switch (nums[2]) {_x000D_
case 1:_x000D_
case 2:_x000D_
case 3:_x000D_
for (i = 0; i < nums[2]; i++) {_x000D_
numsRom[2] += nRom.X;_x000D_
}_x000D_
break;_x000D_
case 4:_x000D_
numsRom[2] += nRom.X + nRom.L;_x000D_
break;_x000D_
case 5:_x000D_
numsRom[2] += nRom.L;_x000D_
break;_x000D_
case 6:_x000D_
case 7:_x000D_
case 8:_x000D_
numsRom[2] += nRom.L;_x000D_
for (i = 0; i < nums[2] - 5; i++) {_x000D_
numsRom[2] += nRom.X;_x000D_
}_x000D_
break;_x000D_
case 9:_x000D_
numsRom[2] += nRom.X + nRom.C;_x000D_
}_x000D_
_x000D_
//1_x000D_
switch (nums[3]) {_x000D_
case 1:_x000D_
case 2:_x000D_
case 3:_x000D_
for (i = 0; i < nums[3]; i++) {_x000D_
numsRom[3] += nRom.I;_x000D_
}_x000D_
break;_x000D_
case 4:_x000D_
numsRom[3] += nRom.I + nRom.V;_x000D_
break;_x000D_
case 5:_x000D_
numsRom[3] += nRom.V;_x000D_
break;_x000D_
case 6:_x000D_
case 7:_x000D_
case 8:_x000D_
numsRom[3] += nRom.V;_x000D_
for (i = 0; i < nums[3] - 5; i++) {_x000D_
numsRom[3] += nRom.I;_x000D_
}_x000D_
break;_x000D_
case 9:_x000D_
numsRom[2] += nRom.I + nRom.X;_x000D_
}_x000D_
_x000D_
return numsRom.join("");_x000D_
}_x000D_
_x000D_
console.log("Number: " + 1234 + " is " + convertToRoman(1234));
_x000D_
This is the first time I really got stuck on freecodecamp. I perused through some solutions here and was amazed at how different they all were. Here is what ended up working for me.
function convertToRoman(num) {
var roman = "";
var lookupObj = {
1000:"M",
900:"CM",
500:"D",
400:"CD",
100:"C",
90:"XC",
50:"L",
40:"XL",
10:"X",
9:"IX",
4:"IV",
5:"V",
1:"I",
};
var arrayLen = Object.keys(lookupObj).length;
while(num>0){
for (i=arrayLen-1 ; i>=0 ; i--){
if(num >= Object.keys(lookupObj)[i]){
roman = roman + lookupObj[Object.keys(lookupObj)[i]];
num = num - Object.keys(lookupObj)[i];
break;
}
}
}
return roman;
}
convertToRoman(1231);
/*my beginner-nooby solution for numbers 1-999 :)*/
function convert(num) {
var RomNumDig = [['','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']];
var lastDig = num%10;
var ourNumb1 = RomNumDig[0][lastDig]||'';
if(num>=10) {
var decNum = (num - lastDig)/10;
if(decNum>9)decNum%=10;
var ourNumb2 = RomNumDig[1][decNum-1]||'';}
if(num>=100) {
var hundNum = ((num-num%100)/100);
var ourNumb3 = RomNumDig[2][hundNum-1]||'';}
return ourNumb3+ourNumb2+ourNumb1;
}
console.log(convert(950));//CML
/*2nd my beginner-nooby solution for numbers 1-10, but it can be easy transformed for larger numbers :)*/
function convert(num) {
var ourNumb = '';
var romNumDig = ['I','IV','V','IX','X'];
var decNum = [1,4,5,9,10];
for (var i=decNum.length-1; i>0; i--) {
while(num>=decNum[i]) {
ourNumb += romNumDig[i];
num -= decNum[i];
}
}
return ourNumb;
}
console.log(convert(9));//IX
Here's a regular expression solution:
function deromanize(roman) {
var r = 0;
// regular expressions to check if valid Roman Number.
if (!/^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/.test(roman))
throw new Error('Invalid Roman Numeral.');
roman.replace(/[MDLV]|C[MD]?|X[CL]?|I[XV]?/g, function(i) {
r += {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}[i];
});
return r;
}
Probably the simplest solution:
rome = n => {_x000D_
b=0_x000D_
s=''_x000D_
for(a=5; n; b++,a^=7)_x000D_
for(o=n%a, n=n/a^0;o--;)_x000D_
s='IVXLCDM'[o>2?b+n-(n&=-2)+(o=1):b]+s_x000D_
return s_x000D_
}_x000D_
_x000D_
r = [rome(892),rome(3999)];_x000D_
_x000D_
console.log(r);
_x000D_
I can't take credit though. This is vetalperko's solution on CodeSignal.
var romanNumerals = [
['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]];
RomanNumerals = {
romerate: function(foo) {
var bar = '';
romanNumerals.forEach(function(buzz) {
while (foo >= buzz[1]) {
bar += buzz[0];
foo -= buzz[1];
}
});
return bar;
},
numerate: function(x) {
var y = 0;
romanNumerals.forEach(function(z) {
while (x.substr(0, z[0].length) == z[0]) {
x = x.substr(z[0].length);
y += z[1];
}
});
return y;
}
};
Having seen all previous 46 solutions for "Number-To-Roman" since this question was asked, there is only one post for the reverse Roman-to-Number by kennebec, and that has several problems: "Number" object cannot be directly extended, you need to use prototype. Also prototyping does not make sense in this context (String object is a better candidate if any). Secondly it is unnecessarily complex and additionally calls toRoman method. Thirdly it fails for numbers greater than 4000. Here is an elegant and and the most concise of all the 47 posts for the both type of conversions. These conversions work for basically any number. The romanToNumber is a small variation of gregoryr's elegant solution:
function numberToRoman(val,rom){ //returns empty string if invalid number_x000D_
rom=rom||''_x000D_
if(isNaN(val)||val==0) _x000D_
return rom;_x000D_
for(i=0;curval=[1000,900,500,400,100,90,50,40,10,9,5,4,1][i],i<13;i++)_x000D_
if(val >= curval)_x000D_
return numberToRoman(val-curval,rom+['M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'][i])_x000D_
}_x000D_
_x000D_
function romanToNumber(txtRom){//returns NaN if invalid string_x000D_
txtRom=txtRom.toUpperCase();_x000D_
if (!/^M*(CM|CD|(D?C{0,3}))?(XC|XL|(L?X{0,3}))?(IX|IV|(V?I{0,3}))?$/.test(txtRom))_x000D_
return NaN;_x000D_
var retval=0;_x000D_
txtRom.replace(/[MDLV]|C[MD]?|X[CL]?|I[XV]?/g, function(i) {_x000D_
retval += {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}[i]; _x000D_
});_x000D_
return retval;_x000D_
}
_x000D_
#tblRoman{border-collapse:collapse;font-family:sans-serif;font-size:.8em}
_x000D_
<h3>Roman to Number Conversion</h3>_x000D_
<input type="button" value="example 1" onclick="document.getElementById('romanval').value='mmmmmmmcdlxxxiv'">_x000D_
<input type="button" value="example 2" onclick="document.getElementById('romanval').value='mmmmmmmdclxxxiv'">_x000D_
<input type="button" value="example 3" onclick="document.getElementById('romanval').value='mmmmmmmdxcdlxxxiv'">_x000D_
<p>_x000D_
Enter a Roman Number below, or click on an example button. Then click Convert _x000D_
</p>_x000D_
<input type="text" size="40" id="romanval">_x000D_
<input type="button" onclick="document.getElementById('resultval').innerText_x000D_
= romanToNumber(document.getElementById('romanval').value)" value="Convert"> _x000D_
<p />_x000D_
Numeric Value: <b id="resultval"></b>_x000D_
_x000D_
<hr>_x000D_
<h3>Number to Roman Conversion</h3>_x000D_
<input type="button" value="Generate table upto 2000" onclick="document.getElementById('tblRoman').innerHTML ='</tr>'+[...Array(2000).keys()].map(x => '<td>'+(x+1)+': '+numberToRoman(x+1)+'</td>'+((x+1)%10==0?'</tr><tr>':'')).join('')+'</tr>'">_x000D_
_x000D_
<table id="tblRoman" border></table>
_x000D_
This solution runs only one loop and has the minimun object to map numerals to roman letters
function RomantoNumeral(r){
let result = 0,
keys = {M:1000, D:500, C:100, L:50, C:100, L:50, X:10, V:5, I:1},
order = Object.keys(keys),
rom = Array.from(r)
rom.forEach((e, i)=>{
if( i < rom.length -1 && order.indexOf(e) > order.indexOf(rom[i+1])){
result -= keys[e]
} else {
result +=keys[e]
}
})
return result
}
RomantoNumeral('MMDCCCXXXVII') #2837
This function will convert any number smaller than 3,999,999 to roman. Notice that numbers bigger than 3999 will be inside a label with text-decoration
set to overline
, this will add the overline
that is the correct representation for x1000 when the number is bigger than 3999.
Four million (4,000,000) would be IV with two overline
s so, you would need to use some trick to represent that, maybe a DIV
with border-top
, or some background image with those two overline
s... Each overline
represents x1000.
function convert(num){
num = parseInt(num);
if (num > 3999999) { alert('Number is too big!'); return false; }
if (num < 1) { alert('Number is too small!'); return false; }
var result = '',
ref = ['M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'],
xis = [1000,900,500,400,100,90,50,40,10,9,5,4,1];
if (num <= 3999999 && num >= 4000) {
num += ''; // need to convert to string for .substring()
result = '<label style="text-decoration: overline;">'+convert(num.substring(0,num.length-3))+'</label>';
num = num.substring(num.length-3);
}
for (x = 0; x < ref.length; x++){
while(num >= xis[x]){
result += ref[x];
num -= xis[x];
}
}
return result;
}
function atalakit (num) {
var result ="";
var roman = ["MMM", "MM", "M", "CM", "DCCC", "DCC", "DC", "D", "CD", "CCC", "CC", "C", "XC", "LXXX", "LXX", "LX", "L", "XL", "XXX", "XX", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I"];
var arabic = [3000, 2000, 1000, 900, 800, 700, 600, 500, 400, 300, 200, 100, 90, 80, 70, 60, 50, 40, 30, 20, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
if ( num>0 && num<4000) {
var arabiclength = arabic.length;
for ( i=0; arabiclength > i; i++) {
if (Math.floor(num/arabic[i])>0){
result += roman[i];
num -= arabic[i];
}
}
}
else {
document.getElementById('text').innerHTML = "too much";
}
document.getElementById('text2').innerHTML = result;
}
function convertToRoman(int) {
console.log('Number:', int);
let roman = [];
let i, k, replacement;
let seq = ['I', 'V', 'X', 'L', 'C', 'D', 'M'];
while (int > 999) {
roman.push('M');
int -= 1000;
}
while (int > 499) {
roman.push('D');
int -= 500;
}
while (int > 99) {
roman.push('C');
int -= 100;
}
while (int > 49) {
roman.push('L');
int -= 50;
}
while (int > 9) {
roman.push('X');
int -= 10;
}
while (int > 4) {
roman.push('V');
int -= 5;
}
while (int >= 1) {
roman.push('I');
int -= 1;
}
// Replace recurrences of 4 ('IIII' to 'IV')
for (i = 0; i < roman.length; i++) {
if (roman[i] == roman[i + 1] &&
roman[i] == roman[i + 2] &&
roman[i] == roman[i + 3]) {
for (k = 0; k < seq.length; k++) {
if (roman[i] == seq[k]) {
replacement = seq[k + 1];
}
}
roman.splice(i + 1, 3, replacement);
}
}
// Converting incorrect recurrences ('VIV' to 'IX')
for (i = 0; i < roman.length; i++) {
if (roman[i] == roman[i + 2] && roman[i] != roman[i + 1]) {
for (k = 0; k < seq.length; k++) {
if (roman[i] == seq[k]) {
replacement = seq[k + 1];
}
}
roman[i + 2] = replacement;
roman.splice(i, 1);
}
}
roman = roman.join('');
return roman;
}
function convertToRoman(num) {
var search = {
"0":["I","II","III","IV","V","VI","VII","VIII","IX"],
"1":["X","XX","XXX","XL","L","LX","LXX","LXXX","XC"],
"2":["C","CC","CCC","CD","D","DC","DCC","DCCC","CM"],
"3":["M","MM","MMM","MV^","V^","V^M","V^MM","V^MMM","MX^"],
};
var numArr = num.toString().split("").reverse();
var romanReturn = [];
for(var i=0; i<numArr.length; i++){
romanReturn.unshift(search[i][numArr[i]-1]);
}
return romanReturn.join("");
}
I am just posting a function I made to convert to Roman, I hope you like it
function converter(numToConv) {
var numToRom = [];
var numToRome = "";
var R = [['M',1000], ['D',500], ['C',100], ['L',50], ['X',10], ['V',5], ['I',1]];
while (numToConv > 0) {
if (numToConv > R[0][1]) {
if (numToConv < R[0][1] * 5 - R[0][1]) {
numToRom.push([R[0][0],"next one goes aftah"]);
numToConv = Math.abs(numToConv - R[0][1]);
console.log("Next comes after: " + R[0][0] + " (" + R[0][1] + ")");
console.log(numToConv);
} else {
numToConv = 0;
break;
}
}
for (var i = 0; i < R.length; i++) {
if (R[i][1] == numToConv) {
numToRom.push([R[i][0],"end"]);
numToConv = Math.abs(numToConv - R[i][1]);
console.log("End: " + numToConv);
} else if (i > 0) {
if ((R[i-1][1] > numToConv) && (R[i][1] < numToConv)) {
console.log(numToConv + " is between: " + R[i][1] + " (" + R[i][0] + ") and: " + R[i - 1][1] + " (" + R[i - 1][0] + ")");
var threshold = R[i - 1][1] - Math.pow(10, numToConv.toString().length - 1);
console.log("threshold: " + threshold + " : " + R[i][1] + " : " + Math.pow(10, numToConv.toString().length - 1));
if (numToConv < threshold) {
numToRom.push([R[i][0],"next one goes aftah"]);
numToConv = Math.abs(numToConv - R[i][1]);
console.log("Next comes after: " + R[i][0] + " (" + R[i][1] + ")");
console.log(numToConv);
} else {
numToRom.push([R[i-1][0],"next one goes befoah"]);
numToConv = Math.abs(numToConv - threshold + Math.pow(10, numToConv.toString().length - 1));
console.log("Next comes before: " + R[i-1][0] + " (" + R[i-1][1] + ")");
console.log(numToConv);
}
}
}
}
}
console.log("numToRom: " + numToRom);
for (var i = 0; i < numToRom.length; i++) {
if (numToRom[i][1] == "next one goes befoah") {
numToRome += (numToRom[i+1][0] + numToRom[i][0]);
console.log("numToRome goes befoah: " + numToRome + " i: " + i);
i++;
} else {
numToRome += numToRom[i][0];
console.log("numToRome goes aftah: " + numToRome + " i: " + i);
}
}
console.log("numToRome: " + numToRome);
return numToRome;
}
The edited code with comments:
function converter(numToConv) {
var numToRom = []; //an array empty, ready to store information about the numbers we will use as we analyse the given number
var numToRome = ""; // this is a string to add the Roman letters forming our returning number
var R = [['M',1000], ['D',500], ['C',100], ['L',50], ['X',10], ['V',5], ['I',1]]; //this array stores the matches with the arabic numbers that we are going to need
while (numToConv > 0) { //just checking, there is no zero
if (numToConv > R[0][1]) { //checks if the number is bigger than the bigger number in the array
if (numToConv < R[0][1] * 5 - R[0][1]) { //checks if it is larger even than 4 times the larger number in the array (just because there is not usually a way to express a number by putting 4 times the same letter i.e there is no "IIII", or "XXXX" etc)
numToRom.push([R[0][0],"next one goes aftah"]);//here is the information we want to pass, we add the letter we are about to use along with info about the next letter
numToConv = Math.abs(numToConv - R[0][1]);// and now we are subtracting the value of the letter we are using from the number
console.log("Next comes after: " + R[0][0] + " (" + R[0][1] + ")");// informing about what we encountering
console.log(numToConv);//..as well as what's the next number
} else { //if the number is larger than 4 times the larger number in the array (thus it cannot be expressed)
numToConv = 0; //then 0 the number (unnecessary but still, no problem doing it)
break;//and of course, breaking the loop, no need to continue
}
}
for (var i = 0; i < R.length; i++) {//now we are about to search our number for each cell of the array with the roman letters (again and again)
if (R[i][1] == numToConv) { //if the number is equal to the one in the cell (that means the conversion is over)
numToRom.push([R[i][0],"end"]); //we pass the information about that cell along with the indication that the conversion has ended
numToConv = Math.abs(numToConv - R[i][1]);//thai can also be skipped but again there is o harm in keeping it
console.log("End: " + numToConv);// again informing about what we encountering
} else if (i > 0) { //just a precaution because we are about to use "i-1"
if ((R[i-1][1] > numToConv) && (R[i][1] < numToConv)) {//we find the range in which is the given number (for instance: the number 4 is between 1[I] and 5[V])
console.log(numToConv + " is between: " + R[i][1] + " (" + R[i][0] + ") and: " + R[i - 1][1] + " (" + R[i - 1][0] + ")");// once again informing
var threshold = R[i - 1][1] - Math.pow(10, numToConv.toString().length - 1);// we create this "threshold" to check if the next number is going before or after this one (difference between 7[VII] and 9[IX]). it is the larger number of our range - 10^[depends on how large is the number we want to convert] (for 999, the threshold is 900, it is smaller 1000 - 10^2)
console.log("threshold: " + threshold + " : " + numToConv + " : " + R[i - 1][1] + " : " + R[i][1] + " : " + Math.pow(10, numToConv.toString().length - 1));
if (numToConv < threshold) {//if the number is smaller than the "threshold" (like 199 where its threshold is 400)
numToRom.push([R[i][0],"next one goes aftah"]);//then the next number is going after
numToConv = Math.abs(numToConv - R[i][1]);//and again, subtract the used value of the number we are converting
console.log("Next comes after: " + R[i][0] + " (" + R[i][1] + ")");
console.log(numToConv);
} else { // now, if the number is larger than the threshold (like 99 where its threshold is 90)
numToRom.push([R[i-1][0],"next one goes befoah"]);// then the next number is going before the one we add now
numToConv = Math.abs(numToConv - R[i - 1][1]);// again, the subtraction, it was "threshold + Math.pow(10, numToConv.toString().length - 1)" but I changed it to "R[i - 1][1]", same result, less operations
console.log("Next comes before: " + R[i-1][0] + " (" + R[i-1][1] + ")");
console.log(numToConv);
}
}
}
}
}
console.log("numToRom: " + numToRom); //now that we have all the info we need about the number, show it to the log (just for a check)
for (var i = 0; i < numToRom.length; i++) {//..and we start running through that info to create our final number
if (numToRom[i][1] == "next one goes befoah") {//if our information about the cell tells us that the next letter is going before the current one
numToRome += (numToRom[i+1][0] + numToRom[i][0]);// we add both to our string (the next one first)
console.log("numToRome goes befoah: " + numToRome + " i: " + i);
i++;//and we add an extra '1' to the i, so it will skip the next letter (mind that there won't be more than one letters saying that the next one is going before them in a row
} else {//if the next one is going after the current one
numToRome += numToRom[i][0]; //we just add the one we are on to the string and go forth
console.log("numToRome goes aftah: " + numToRome + " i: " + i);
}
}
console.log("numToRome: " + numToRome);
return numToRome;//return the string and we are done
}
function convertToRoman(num) {_x000D_
_x000D_
var romans = {_x000D_
1000: 'M',_x000D_
900: 'CM',_x000D_
500: 'D',_x000D_
400: 'CD',_x000D_
100: 'C',_x000D_
90: 'XC',_x000D_
50: 'L',_x000D_
40: 'XL',_x000D_
10: 'X',_x000D_
9: 'IX',_x000D_
5: 'V',_x000D_
4: 'IV',_x000D_
1: 'I'_x000D_
};_x000D_
var popped, rem, roman = '',_x000D_
keys = Object.keys(romans);_x000D_
while (num > 0) {_x000D_
popped = keys.pop();_x000D_
m = Math.floor(num / popped);_x000D_
num = num % popped;_x000D_
console.log('popped:', popped, ' m:', m, ' num:', num, ' roman:', roman);_x000D_
while (m-- > 0) {_x000D_
roman += romans[popped];_x000D_
}_x000D_
while (num / popped === 0) {_x000D_
popped = keys.pop();_x000D_
delete romans[popped];_x000D_
}_x000D_
}_x000D_
return roman;_x000D_
}_x000D_
var result = convertToRoman(3999);_x000D_
console.log(result);_x000D_
document.getElementById('roman').innerHTML = 'Roman: ' + result;
_x000D_
p {_x000D_
color: darkblue;_x000D_
}
_x000D_
<p>Decimal: 3999</p>_x000D_
<p id="roman">Roman:</p>
_x000D_
While my answer is not as performant as others, my focus was more on not hard coding in base numbers and allowing the program to figure out the rest.
For example...
Instead of:
number = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
numeral = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I']
I used:
base = ['I', 'X', 'C', 'M'];
pivot = ['V', 'L', 'D'];
function basicRomanNumerals(num){
let base = ['I', 'X', 'C', 'M'];
let pivot = ['V', 'L', 'D'];
return String(num).split('').reverse().map(function(num, idx){
let distance = +num - 5;
let is1AwayFromNext = Math.abs(+num - 10) === 1;
if(Math.abs(distance)=== 1 || is1AwayFromNext){
if(is1AwayFromNext){
return base[idx]+""+base[idx+1];
}else if ( distance < 0 ){
return base[idx]+""+pivot[idx];
}else{
return pivot[idx]+""+base[idx];
}
}else if(distance === 0){
return pivot[idx];
}else if(distance > 1){
return pivot[idx]+""+base[idx].repeat(+num-5);
}else{
return base[idx].repeat(+num);
}
}).reverse().join('');
After testing some of the implementations in this post, I have created a new optimized one in order to execute faster. The time execution is really low comparing with the others, but obviously the code is uglier :). It could be even faster with an indexed array with all the posibilities. Just in case it helps someone.
function concatNumLetters(letter, num) {
var text = "";
for(var i=0; i<num; i++){
text += letter;
}
return text;
}
function arabicToRomanNumber(arabic) {
arabic = parseInt(arabic);
var roman = "";
if (arabic >= 1000) {
var thousands = ~~(arabic / 1000);
roman = concatNumLetters("M", thousands);
arabic -= thousands * 1000;
}
if (arabic >= 900) {
roman += "CM";
arabic -= 900;
}
if (arabic >= 500) {
roman += "D";
arabic -= 500;
}
if (arabic >= 400) {
roman += "CD";
arabic -= 400;
}
if (arabic >= 100) {
var hundreds = ~~(arabic / 100);
roman += concatNumLetters("C", hundreds);
arabic -= hundreds * 100;
}
if (arabic >= 90) {
roman += "XC";
arabic -= 90;
}
if (arabic >= 50) {
roman += "L";
arabic -= 50;
}
if (arabic >= 40) {
roman += "XL";
arabic -= 40;
}
if (arabic >= 10) {
var dozens = ~~(arabic / 10);
roman += concatNumLetters("X", dozens);
arabic -= dozens * 10;
}
if (arabic >= 9) {
roman += "IX";
arabic -= 9;
}
if (arabic >= 5) {
roman += "V";
arabic -= 5;
}
if (arabic >= 4) {
roman += "IV";
arabic -= 4;
}
if (arabic >= 1) {
roman += concatNumLetters("I", arabic);
}
return roman;
}
function convertToRoman(num) {_x000D_
var toTen = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"];_x000D_
var toHungred = ["", "X" ,"XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "C"];_x000D_
var toThousend = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "M"]; _x000D_
var arrString = String(num).split(""); _x000D_
var arr = []; _x000D_
if (arrString.length == 3 ){ _x000D_
arr.push(toThousend[arrString[+0]]);_x000D_
arr.push(toHungred[arrString[+1]]);_x000D_
arr.push(toTen[arrString[+2]]);_x000D_
} _x000D_
else if (arrString.length == 2 ){ _x000D_
arr.push(toHungred[arrString[+0]]);_x000D_
arr.push(toTen[arrString[+1]]); _x000D_
}_x000D_
else if (arrString.length == 1 ){ _x000D_
arr.push(toTen[arrString[+0]]); _x000D_
}_x000D_
else if (arrString.length == 4 ) {_x000D_
for (var i =1; i<=[arrString[+0]]; i++) {_x000D_
arr.push("M"); _x000D_
}_x000D_
arr.push(toThousend[arrString[+1]]);_x000D_
arr.push(toHungred[arrString[+2]]);_x000D_
arr.push(toTen[arrString[+3]]);_x000D_
} _x000D_
console.log (arr.join(""));_x000D_
}_x000D_
_x000D_
convertToRoman(36);
_x000D_
I don't understand why everyones solution is so long and uses multiple for loops.
function convertToRoman(num) {
var roman = {
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
};
var str = '';
for (var i of Object.keys(roman)) {
var q = Math.floor(num / roman[i]);
num -= q * roman[i];
str += i.repeat(q);
}
return str;
}
My solution breaks the number in to an array of strings, adds zeros to each element based on its position relative to the length of the array, converts the new strings with zeros to roman numerals, and then joins them back together. This will only work with numbers up to 3999:
function convertToRoman(num){
var rnumerals = { 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'};
var zeros, romNum;
var arr = num.toString().split("");
var romArr = [];
for(var i=0; i < arr.length; i++){
zeros = "0".repeat((arr.length - i - 1));
arr[i] = arr[i].concat(zeros);
romArr.push(rnumerals[(arr[i])]);
}
romNum = romArr.join('');
return romNum;
}
function convertToRoman(num) {_x000D_
var arr = [];_x000D_
for (var i = 0; i < num.toString().length; i++) {_x000D_
arr.push(Number(num.toString().substr(i, 1)));_x000D_
}_x000D_
var romanArr = [_x000D_
["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"],_x000D_
["X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"],_x000D_
["C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"],_x000D_
["M"]_x000D_
];_x000D_
var roman = arr.reverse().map(function (val, i) {_x000D_
if (val === 0) {_x000D_
return "";_x000D_
}_x000D_
if (i === 3) {_x000D_
var r = "";_x000D_
for (var j = 0; j < val; j++) {_x000D_
r += romanArr[i][0];_x000D_
}_x000D_
return r;_x000D_
} else {_x000D_
return romanArr[i][val - 1];_x000D_
}_x000D_
});_x000D_
console.log(roman.reverse().join(""));_x000D_
return roman.join("");_x000D_
}_x000D_
_x000D_
_x000D_
convertToRoman(10);
_x000D_
Here is my code,Hope this helpful:
function convertToRoman(num) {_x000D_
let numArr = [];//[M,D,C,L,X,V,I]_x000D_
let numStr = "";_x000D_
_x000D_
//get num Array_x000D_
numArr.push(parseInt(num / 1000));_x000D_
num %= 1000;_x000D_
numArr.push(parseInt(num / 500));_x000D_
num %= 500;_x000D_
numArr.push(parseInt(num / 100));_x000D_
num %= 100;_x000D_
numArr.push(parseInt(num / 50));_x000D_
num %= 50;_x000D_
numArr.push(parseInt(num / 10));_x000D_
num %= 10;_x000D_
numArr.push(parseInt(num / 5));_x000D_
num %= 5;_x000D_
numArr.push(num);_x000D_
_x000D_
//cancat num String_x000D_
for(let i = 0; i < numArr.length; i++) {_x000D_
switch(i) {_x000D_
case 0://M_x000D_
for(let j = 0; j < numArr[i]; j++) {_x000D_
numStr = numStr.concat("M");_x000D_
}_x000D_
break;_x000D_
case 1://D_x000D_
switch(numArr[i]) {_x000D_
case 0:_x000D_
_x000D_
break;_x000D_
case 1:_x000D_
if(numArr[i + 1] === 4) {_x000D_
numStr = numStr.concat("CM");_x000D_
i++;_x000D_
}else {_x000D_
numStr = numStr.concat("D");_x000D_
}_x000D_
break;_x000D_
}_x000D_
break;_x000D_
case 2://C_x000D_
switch(numArr[i]) {_x000D_
case 0:_x000D_
_x000D_
break;_x000D_
case 1:_x000D_
numStr = numStr.concat("C");_x000D_
break;_x000D_
case 2:_x000D_
numStr = numStr.concat("CC");_x000D_
break;_x000D_
case 3:_x000D_
numStr = numStr.concat("CCC");_x000D_
break;_x000D_
case 4:_x000D_
numStr = numStr.concat("CD");_x000D_
break;_x000D_
}_x000D_
break;_x000D_
case 3://L_x000D_
switch(numArr[i]) {_x000D_
case 0:_x000D_
_x000D_
break;_x000D_
case 1:_x000D_
if(numArr[i + 1] === 4) {_x000D_
numStr = numStr.concat("XC");_x000D_
i++;_x000D_
}else {_x000D_
numStr = numStr.concat("L");_x000D_
}_x000D_
break;_x000D_
}_x000D_
break;_x000D_
case 4://X_x000D_
switch(numArr[i]) {_x000D_
case 0:_x000D_
_x000D_
break;_x000D_
case 1:_x000D_
numStr = numStr.concat("X");_x000D_
break;_x000D_
case 2:_x000D_
numStr = numStr.concat("XX");_x000D_
break;_x000D_
case 3:_x000D_
numStr = numStr.concat("XXX");_x000D_
break;_x000D_
case 4:_x000D_
numStr = numStr.concat("XL");_x000D_
break;_x000D_
}_x000D_
break;_x000D_
case 5://V_x000D_
switch(numArr[i]) {_x000D_
case 0:_x000D_
_x000D_
break;_x000D_
case 1:_x000D_
if(numArr[i + 1] === 4) {_x000D_
numStr = numStr.concat("IX");_x000D_
i++;_x000D_
}else {_x000D_
numStr = numStr.concat("V");_x000D_
}_x000D_
break;_x000D_
}_x000D_
break;_x000D_
case 6://I_x000D_
switch(numArr[i]) {_x000D_
case 0:_x000D_
_x000D_
break;_x000D_
case 1:_x000D_
numStr = numStr.concat("I");_x000D_
break;_x000D_
case 2:_x000D_
numStr = numStr.concat("II");_x000D_
break;_x000D_
case 3:_x000D_
numStr = numStr.concat("III");_x000D_
break;_x000D_
case 4:_x000D_
numStr = numStr.concat("IV");_x000D_
break;_x000D_
}_x000D_
break;_x000D_
}_x000D_
}_x000D_
console.log(numStr);_x000D_
return numStr;_x000D_
}_x000D_
_x000D_
convertToRoman(3999);
_x000D_
A strings way: (for M chiffer and below)
const romanNumerals = [
['I', 'V', 'X'],//for ones 0-9
['X', 'L', 'C'],//for tens 10-90
['C', 'D', 'M'] //for hundreds 100-900
];
function romanNumUnderThousand(dijit, position) {
let val = '';
if (position < 3) {
const [a, b, c] = romanNumerals[position];
switch (dijit) {
case '1': val = a; break;
case '2': val = a + a; break;
case '3': val = a + a + a; break;
case '4': val = a + b; break;
case '5': val = b; break;
case '6': val = b + a; break;
case '7': val = b + a + a; break;
case '8': val = b + a + a + a; break;
case '9': val = a + c; break;
}
}
return val;
}
function convertToRoman(num) {
num = parseInt(num);
const str_num = num.toString();
const lastIndex = str_num.length - 1;
return [
`${(num > 999) ? 'M'.repeat(parseInt(str_num.slice(0, lastIndex - 2))) : ''}`,
`${(num > 99) ? romanNumUnderThousand(str_num[lastIndex - 2], 2) : ''}`,
`${(num > 9) ? romanNumUnderThousand(str_num[lastIndex - 1], 1) : ''}`,
romanNumUnderThousand(str_num[lastIndex], 0)
].join('');
}
convertToRoman(36);
Here's mine;
function convertToRoman(num) {
let decimalValueArray = [1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000, "bigger"];
let romanNumArray = ["I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M"];
let resultNumArray = [];
function getRoman(num) {
for (let i = 0; i < decimalValueArray.length; i++) {
let decimalElem = decimalValueArray[i];
if (num === decimalElem || num === 0) {
resultNumArray.push(romanNumArray[i]);
return ;
} else if (decimalElem > num || decimalElem === "bigger") { //using (decimalElem>num) and then array value of(i-1) to get the highest decimal value from the array.but this doesnt work when highest decimel value is 1000.so added "bigger" element.
resultNumArray.push(romanNumArray[i - 1]);
getRoman(num - (decimalValueArray[i - 1]));
} else {
continue;
}
return;
}
}
getRoman(num);
let resultNumber = (resultNumArray.join(""));
return(resultNumber); }
I know this is a dated question but I have the shortest solution of the ones listed here and thought I would share since I think its easier to understand.
This version does not require any hard coded logic for edge cases such as 4(IV),9(IX),40(XL),900(CM), etc. as the others do. This also means it can handle larger numbers greater than the maximum roman scale could (3999). For example if "T" became a new symbol you could add it to the beginning of the romanLookup object and it would keep the same algorithmic affect; or course assuming the "no more than 3 of the same symbol in a row" rule applies.
I have tested this against a data set from 1-3999 and it works flawlessly.
function convertToRoman(num) {
//create key:value pairs
var romanLookup = {M:1000, D:500, C:100, L:50, X:10, V:5, I:1};
var roman = [];
var romanKeys = Object.keys(romanLookup);
var curValue;
var index;
var count = 1;
for(var numeral in romanLookup){
curValue = romanLookup[numeral];
index = romanKeys.indexOf(numeral);
while(num >= curValue){
if(count < 4){
//push up to 3 of the same numeral
roman.push(numeral);
} else {
//else we had to push four, so we need to convert the numerals
//to the next highest denomination "coloring-up in poker speak"
//Note: We need to check previous index because it might be part of the current number.
//Example:(9) would attempt (VIIII) so we would need to remove the V as well as the I's
//otherwise removing just the last three III would be incorrect, because the swap
//would give us (VIX) instead of the correct answer (IX)
if(roman.indexOf(romanKeys[index - 1]) > -1){
//remove the previous numeral we worked with
//and everything after it since we will replace them
roman.splice(roman.indexOf(romanKeys[index - 1]));
//push the current numeral and the one that appeared two iterations ago;
//think (IX) where we skip (V)
roman.push(romanKeys[index], romanKeys[index - 2]);
} else {
//else Example:(4) would attemt (IIII) so remove three I's and replace with a V
//to get the correct answer of (IV)
//remove the last 3 numerals which are all the same
roman.splice(-3);
//push the current numeral and the one that appeared right before it; think (IV)
roman.push(romanKeys[index], romanKeys[index - 1]);
}
}
//reduce our number by the value we already converted to a numeral
num -= curValue;
count++;
}
count = 1;
}
return roman.join("");
}
convertToRoman(36);
Here is my solution:
function convertToRoman(num) {
let romanNum = "";
const strNum = String(num);
const romans = {
1: ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"], // ones
2: ["X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"], // tens
3: ["C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"], // hundreds
4: ["M", "MM", "MMM"] // thousands
};
for (let i = 1; i <= strNum.length; i++)
if (Number(strNum[strNum.length - i]) !== 0)
romanNum = romans[i][strNum[strNum.length - i] - 1] + romanNum;
return romanNum;
}
It performs quite well in Chrome 60 - https://jsperf.com/num-to-roman
If you want to convert a big number with more symbols, maybe this algo could help.
The only premise for symbols is that must be odd and follow the same rule (1, 5, 10, 50,100 ...., 10^(N)/2, 10^(N)).
var rnumbers = ["I","V","X","L","C","D","M"];_x000D_
rnumbers = rnumbers.concat(["V","X","L","C","D","M"].map(function(n) {return '<span style="border-top:1px solid black; padding:1px;">'+n+'</span> '}));_x000D_
rnumbers = rnumbers.concat(["V","X","L","C","D","M"].map(function(n) {return '<span style="border:1px solid black; border-bottom:1px none black; padding:1px;">'+n+'</span> '}));_x000D_
rnumbers = rnumbers.concat(["V","X","L","C","D","M"].map(function(n) {return '<span style="border-top:3px double black; padding:1px;">'+n+'</span> '}));_x000D_
_x000D_
_x000D_
String.prototype.repeat = function( num ) {_x000D_
return new Array( num + 1 ).join( this );_x000D_
};_x000D_
_x000D_
function toRoman(n) {_x000D_
_x000D_
if(!n) return "";_x000D_
_x000D_
var strn = new String(n);_x000D_
var strnlength = strn.length;_x000D_
var ret = "";_x000D_
for(var i = 0 ; i < strnlength; i++) {_x000D_
var index = strnlength*2 -2 - i*2;_x000D_
var str;_x000D_
var m = +strn[i];_x000D_
if(index > rnumbers.length -1) {_x000D_
str = rnumbers[rnumbers.length-1].repeat(m*Math.pow(10,Math.ceil((index-rnumbers.length)/2)));_x000D_
}else {_x000D_
str = rnumbers[index].repeat(m);_x000D_
if (rnumbers.length >= index + 2) {_x000D_
var rnregexp = rnumbers[index]_x000D_
.split("(").join('\\(')_x000D_
.split(")").join('\\)');_x000D_
_x000D_
str = str.replace(new RegExp('(' + rnregexp + '){9}'), rnumbers[index] + rnumbers[index + 2])_x000D_
.replace(new RegExp('(' + rnregexp + '){5}'), rnumbers[index + 1])_x000D_
.replace(new RegExp('(' + rnregexp + '){4}'), rnumbers[index] + rnumbers[index + 1])_x000D_
}_x000D_
}_x000D_
ret +=str;_x000D_
}_x000D_
_x000D_
return ret;_x000D_
}
_x000D_
_x000D_
<input type="text" value="" onkeyup="document.getElementById('result').innerHTML = toRoman(this.value)"/>_x000D_
_x000D_
<br/><br/>_x000D_
_x000D_
<div id="result"></div>
_x000D_
This works for all numbers only in need of roman numerals M and below.
function convert(num) {
var code = [
[1000, "M"], [900, "CM"], [800, "DCCC"], [700, "DCC"], [600, "DC"],
[500, "D"], [400, "CD"], [300, "CCC"], [200, "CC"],
[100, "C"], [90, "XC"], [80, "LXXX"], [70, "LXX"], [60, "LX"],
[50, "L"], [40, "XL"], [30, "XXX"], [20, "XX"],
[10, "X"], [9, "IX"], [8, "VIII"], [7, "VII"], [6, "VI"],
[5, "V"], [4, "IV"], [3, "III"], [2, "II"], [1, "I"],
];
var rom = "";
for(var i=0; i<code.length; i++) {
while(num >= code[i][0]) {
rom += code[i][1];
num -= code[i][0];
}
}
return rom;
}
I just made this at freecodecamp. It can easily be expanded.
function convertToRoman(num) {
var roman ="";
var values = [1000,900,500,400,100,90,50,40,10,9,5,4,1];
var literals = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"];
for(i=0;i<values.length;i++){
if(num>=values[i]){
if(5<=num && num<=8) num -= 5;
else if(1<=num && num<=3) num -= 1;
else num -= values[i];
roman += literals[i];
i--;
}
}
return roman;
}
Nice responses. You can get this done programmatically without hardcoding the values too much. Only that your code will be a little longer.
const convertToRoman = (arabicNum) => {
const roman_benchmarks = {1: 'I', 5: 'V', 10: 'X', 50: 'L', 100: 'C', 500: 'D', 1000: 'M', 5000: '_V', 10000: '_X', 50000: '_L', 100000: '_C'};
// in the future, you can add higher numbers with their corresponding roman symbols/letters and the program will adjust to the change
const arabic_benchmarks = [1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000]; // don't forget to include the new numbers here too
arabicNum = parseInt(arabicNum);
let proceed = parseInt(arabicNum.toString().length);
let romanNumeral = '';
while(proceed){ // the loop continues as long as there's still a unit left in arabicNum
const temp_denominator = 1 * (10**(arabicNum.toString().length-1)); // determine what multiple of 10 arabicNum is
const multiple = Math.floor(arabicNum/temp_denominator); // get its first digit
const newNum = multiple*temp_denominator; // regenerate a floored version of arabicNum
const filtered_two = arabic_benchmarks.filter((x, i) => newNum >= x && newNum<= arabic_benchmarks[i+1] || newNum <= x && newNum>= arabic_benchmarks[i-1]);
// filter arabic_benchmarks for the 2 boundary numbers newNum falls within
switch (newNum) { // check for what roman numeral best describes newNum and assign it to romanNumeral
case (newNum == filtered_two[0]-temp_denominator ? newNum :''):
romanNumeral += roman_benchmarks[temp_denominator]+roman_benchmarks[filtered_two[0]]
break;
case (newNum == filtered_two[0] ? newNum : ''):
romanNumeral += roman_benchmarks[filtered_two[0]]
break;
case (newNum > filtered_two[0] && newNum < (filtered_two[1]-temp_denominator) ? newNum : ''):
romanNumeral += roman_benchmarks[filtered_two[0]]
const factor = multiple < 5 ? (multiple%5)-1 : multiple%5;
for(let i = 0; i < factor; i++){
romanNumeral += roman_benchmarks[temp_denominator];
}
break;
case (newNum == filtered_two[1]-temp_denominator ? newNum : ''):
romanNumeral += roman_benchmarks[temp_denominator]+roman_benchmarks[filtered_two[1]];
break;
case (newNum == filtered_two[1] ? newNum : ''):
romanNumeral += roman_benchmarks[filtered_two[1]];
break;
default:
break;
}
arabicNum = arabicNum - newNum; // reduce arabicNum by its first hierarchy
proceed--; // continue the loop
}
return romanNumeral;
}
var romanToInt = function(s) {
var sum = [];
var obj = {"I":1,"V":5,"X":10,"L":50,"C":100,"D":500,"M":1000};
for(var i=0;i<s.length;i++){
if(obj[s[i]]>obj[s[i-1]]){
sum[i-1] = (obj[s[i]]-obj[s[i-1]])
}else{
sum[i]=(obj[s[i]])
}
}
return sum.reduce((a, b) => a + b, 0);
};
The above code uses an object to look up the values and calculate accordingly.
var romanToInt = function(s) {
var sum = [];
for(var i=0;i<s.length;i++){
if(s[i]=="I"){
sum.push(1);
}else if(s[i]=="V"){
sum.push(5);
}else if(s[i]=="X"){
sum.push(10);
}else if(s[i]=="L"){
sum.push(50);
}else if(s[i]=="C"){
sum.push(100);
}else if(s[i]=="D"){
sum.push(500);
}else if(s[i]=="M"){
sum.push(1000);
}
if(sum[i-1]<sum[i]){
sum[i] = sum[i]-sum[i-1]
sum[i-1] = 0
}else{
sum[i] = sum[i]
}
}
return sum.reduce((a, b) => a + b, 0)
};
The code in the above case uses the if/else-if statement to carry out the same operation. This method executes faster and is also memory efficient.
It can be worked out with switch statement also in the following way.
var romanToInt = function(s) {
var sum = [];
for(var i=0;i<s.length;i++){
switch(s[i]){
case "I":
sum.push(1);
break;
case "V":
sum.push(5);
break;
case "X":
sum.push(10);
break;
case "L":
sum.push(50);
break;
case "C":
sum.push(100);
break;
case "D":
sum.push(500);
break;
case "M":
sum.push(1000);
break;
}
if(sum[i-1]<sum[i]){
sum[i] = sum[i]-sum[i-1]
sum[i-1] = 0
}else{
sum[i] = sum[i]
}
}
return sum.reduce((a, b) => a + b, 0)
};
const convertToRoman = (n)=>
{
let u =0;
let result ='';
let rL='IVXLCDM';
while (n>0)
{
u=n%10;
switch (u){
case 1: result = rL[0] + result ;
break;
case 2: result = rL[0]+rL[0] + result;
break;
case 3: result = rL[0]+rL[0]+rL[0] + result;
break;
case 4: result = rL[0]+rL[1] + result;
break;
case 5: result = rL[1] + result;
break;
case 6: result = rL[1] + rL[0] + result;
break;
case 7: result =rL[1] + rL[0] +rL[0] + result;
break;
case 8: result = rL[1] + rL[0] +rL[0] + rL[0] + result;
break;
case 9: result = rL[0] + rL[2] + result;
break;
};
rL = rL.substring(2)
// after every last digit.. when conversion is finished..
// number is taking another value - same as container with roman Letter
n=Math.trunc(n/10);
};
return result;
};
I'm beginner, and I see like that ))) without arrays . of course it would be better with itter + acc in function.. Just passed test at freeCodeCamp
Still proud of it :) It works between 1-3999.
var converterArray = [{"1":["I","IV","V","IX"],
"2":["X","XL","L","XC"],
"3":["C","CD","D","CM"],
"4":["M"]}
];
function convertToRoman(num) {
var romanNumeral = [];
var numArr = num.toString().split('');
var numLength = numArr.length;
for (var i = 0; i<numArr.length; i++) {
if (numArr[i] < 4) {
for (var j = 0; j<numArr[i]; j++) {
romanNumeral.push(converterArray[0][numLength][0]);
}
} else if (numArr[i] < 5) {
for (var j = 3; j<numArr[i]; j++) {
romanNumeral.push(converterArray[0][numLength][1]);
}
} else if (numArr[i] < 9) {
romanNumeral.push(converterArray[0][numLength][2]);
for (var j = 5; j<numArr[i]; j++) {
romanNumeral.push(converterArray[0][numLength][0]);
}
} else if (numArr[i] < 10) {
for (var j = 8; j<numArr[i]; j++) {
romanNumeral.push(converterArray[0][numLength][3]);
}
}
numLength--;
}
return romanNumeral.join('');
}
convertToRoman(9);
I've developed the recursive solution below. The function returns one letter and then calls itself to return the next letter. It does it until the number passed to the function is 0
which means that all letters have been found and we can exit the recursion.
var romanMatrix = [
[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']
];
function convertToRoman(num) {
if (num === 0) {
return '';
}
for (var i = 0; i < romanMatrix.length; i++) {
if (num >= romanMatrix[i][0]) {
return romanMatrix[i][1] + convertToRoman(num - romanMatrix[i][0]);
}
}
}
I created two twin arrays one with arabic numbers the other with the roman characters.
function convert(num) {_x000D_
_x000D_
var result = '';_x000D_
var rom = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];_x000D_
var ara = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
_x000D_
Then I added a cycle which scan the roman elements, adding the biggest still comprised in NUM to RESULT, then we decrease NUM of the same amount.
It is like we map a part of NUM in roman numbers and then we decrease it of the same amount.
for (var x = 0; x < rom.length; x++) {_x000D_
while (num >= ara[x]) {_x000D_
result += rom[x];_x000D_
num -= ara[x];_x000D_
}_x000D_
}_x000D_
return result;_x000D_
}
_x000D_
This is my solution, I'm not too sure how well it performs.
function convertToRoman(num) {
var uni = ["","I","II","III","IV","V","VI","VII","VIII","IX"];
var dec = ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"];
var cen = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"];
var mil = ["","M","MM","MMM","MMMM","MMMMM","MMMMMM","MMMMMMM","MMMMMMMM","MMMMMMMMMM"];
var res =[];
if(num/1000 > 0)
{
res = res.concat(mil[Math.floor(num/1000)]);
}
if(num/100 > 0)
{
res = res.concat(cen[Math.floor((num%1000)/100)]);
}
if(num/10 >0)
{
res = res.concat(dec[Math.floor(((num%1000)%100)/10)]);
}
res=res.concat(uni[Math.floor(((num%1000)%100)%10)]);
return res.join('');
}
I just completed this on freeCodeCamp too, I didn't see this particular solution. I know this solution can be optimized with recursion but I just wanted to throw it out there so at least you can see other options:
function convertToRoman(num) {
var value = [];
var temp, base, buffer;
var letters = ['I', 'V', 'X', 'L', 'C', 'D', 'M'];
var offsets = [
[1, 0], // 1
[2, 0], // 2
[3, 0], // 3
[-1, 1], // 4
[0, 1], // 5
[1, 1], // 6
[2, 1], // 7
[3, 1], // 8
[-2, 2], // 9
];
// cascade through each denomination (1000's, 100's, 10's, 1's) so that each denomination is triggered
// Thousands
if (num >= 1000) {
temp = Math.floor(num / 1000);
buffer = offsets[temp - 1];
base = 6;
value.push(getValue(base, letters, buffer));
num -= temp * 1000;
}
// Hundreds
if (num >= 100) {
temp = Math.floor(num / 100);
buffer = offsets[temp - 1];
base = 4;
value.push(getValue(base, letters, buffer));
num -= temp * 100;
}
// Tens
if (num >= 10) {
temp = Math.floor(num / 10);
buffer = offsets[temp - 1];
base = 2;
value.push(getValue(base, letters, buffer));
num -= temp * 10;
}
// Ones
if (num > 0) {
buffer = offsets[num - 1];
base = 0;
value.push(getValue(base, letters, buffer));
}
// Finish
return value.join('');
}
function getValue(base, letters, buffer) {
var val1 = buffer[0], val2 = buffer[1];
var value = [];
// If val1 is less than 0 then we know it is either a 4 or 9, which has special cases
if (val1 < 0) {
// Push the base index, then push the base plus the val2 offset
value.push(letters[base]);
value.push(letters[base + val2]);
} else {
// Push a letter if val2 is set - meaning we need to offset a number that is equal to or higher than 5
// 5 is basically the only scenario which this will exist
if (val2 > 0) value.push(letters[base + val2]);
// Now add in the next letters of the base for the inciment
for (var i = 0; i < val1; i++) {
value.push(letters[base]);
}
}
return value.join('');
}
convertToRoman(90);
I'm pretty sure the companion function means it can have almost limitless potential, assuming you provide the correct symbols for numbers larger than M, but don't quote me on that.
These functions convert any positive whole number to its equivalent Roman Numeral string; and any Roman Numeral to its number.
Number to Roman Numeral:
Number.prototype.toRoman= function () {
var num = Math.floor(this),
val, s= '', i= 0,
v = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
r = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
function toBigRoman(n) {
var ret = '', n1 = '', rem = n;
while (rem > 1000) {
var prefix = '', suffix = '', n = rem, s = '' + rem, magnitude = 1;
while (n > 1000) {
n /= 1000;
magnitude *= 1000;
prefix += '(';
suffix += ')';
}
n1 = Math.floor(n);
rem = s - (n1 * magnitude);
ret += prefix + n1.toRoman() + suffix;
}
return ret + rem.toRoman();
}
if (this - num || num < 1) num = 0;
if (num > 3999) return toBigRoman(num);
while (num) {
val = v[i];
while (num >= val) {
num -= val;
s += r[i];
}
++i;
}
return s;
};
Roman Numeral string to Number:
Number.fromRoman = function (roman, accept) {
var s = roman.toUpperCase().replace(/ +/g, ''),
L = s.length, sum = 0, i = 0, next, val,
R = { M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 };
function fromBigRoman(rn) {
var n = 0, x, n1, S, rx =/(\(*)([MDCLXVI]+)/g;
while ((S = rx.exec(rn)) != null) {
x = S[1].length;
n1 = Number.fromRoman(S[2])
if (isNaN(n1)) return NaN;
if (x) n1 *= Math.pow(1000, x);
n += n1;
}
return n;
}
if (/^[MDCLXVI)(]+$/.test(s)) {
if (s.indexOf('(') == 0) return fromBigRoman(s);
while (i < L) {
val = R[s.charAt(i++)];
next = R[s.charAt(i)] || 0;
if (next - val > 0) val *= -1;
sum += val;
}
if (accept || sum.toRoman() === s) return sum;
}
return NaN;
};
Source: Stackoverflow.com