Convert a number into a Roman numeral in JavaScript
Asked Answered
D

96

96

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

Dative answered 31/1, 2012 at 16:22 Comment(0)
A
134

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;
}
Ammerman answered 31/1, 2012 at 16:24 Comment(3)
Reminder: This should better return NaN or throw instead of returning false as discussed in that post.Villus
I have just found out that the largest number that works with this function is 715799999999 (715,799,999,999). Larger numbers either don’t return anything or (for very large numbers) it outputs RangeError: Invalid array length error. Otherwise, it works perfectly. Thanks!Snuggery
@Snuggery luckily roman numerals are intended for years, otherwise there would be numbers larger than 1000. But it's good to know!Ammerman
C
115
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

VIEW DEMO

Cruce answered 29/9, 2015 at 18:24 Comment(10)
Objects have no order! You should use an array and avoid for...in.Leifeste
@Oriol: It is fairly simple, use the biggest numbers until it can't anymore, otherwise try the next smallest in line. I wasn't able to find a faster method than this. I believe objects are faster than arrays in this case. If you can figure out how to get even better performance, please post an example. Thanks for the feedback and advice!Cruce
I'm not talking about performance. I'm saying that the iteration order is not guaranteed, so the result may be completely wrong.Leifeste
@Oriol, please show an example of a case where a javascript object iteration order will not be guaranteed. Otherwise I believe you are trollingCruce
I can't give an non-working example, because the order is implementation dependent. Instead, please link me which part of the spec ensures it will be iterated with the desired order. Oh, you can't.Leifeste
There might be an implementation out there where it doesn't work. But so far tested working in node, chrome, firefox, and IECruce
objects have no order so I implemented it as a list of pairs [{M:1000}, ...]Luzluzader
@Cruce Here is an example where the order changes in some browsers: for (let i in { '2': 2, '1': 1 }) console.log(i);. Furthermore even if you test it, it does not mean that it always works. There might be cases where a browser changes the order for performance reasons or whatever reasons. You can only be sure, if you know the source code of every version of browser that you support and want to support in the future.Athal
Update, June 2021: As of ES2020, object iteration order, even in for...in loops, is guaranteed to be the same as the object's property order. To be a little pedantic in response to @Oriol, objects do have "order" as of ES2015, but their iteration order was not guaranteed to be the same as the property order when using for...in until recently.Windsail
One thing to note is that, as @Athal demonstrates, the order is not necessarily just "the order in which the keys were written in the source code". But in the context of this answer, since there are no integer/Symbol keys, it makes no difference.Windsail
C
81

I don't understand why everyone's 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;
}
Cassiecassil answered 28/12, 2016 at 8:41 Comment(2)
I think I finally understand this solution. Would adding 'if (num===0){return str}' make it so you loop even less? You can place it at the end of the loop and remove the 'return str'.Palumbo
Yes @kite, nicely spotted ! It would make it loop less, however, considering that we are only looping through 13 items, it won't make much of a difference :)Cassiecassil
C
35

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]);
    }
  }
}
Capitoline answered 9/6, 2016 at 10:51 Comment(0)
I
20

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.

Infection answered 2/7, 2015 at 14:49 Comment(0)
P
17

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;
};
Pyrophoric answered 31/1, 2012 at 17:14 Comment(0)
J
13

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.

I have tested this code against a data set from 1-3999 and it works.

TLDR;

This also means this solution can handle numbers greater than the maximum roman scale could (3999).

It appears there is an alternating rule for deciding the next major roman numeral character. Starting with I multiply by 5 to get the next numeral V and then by 2 to get X, then by 5 to get L, and then by 2 to get C, etc to get the next major numeral character in the scale. In this case lets assume "T" gets added to the scale to allow for larger numbers than 3999 which the original roman scale allows. In order to maintain the same algorithm "T" would represent 5000.

I = 1
V = I * 5
X = V * 2
L = X * 5
C = L * 2
D = C * 5
M = D * 2
T = M * 5

This could then allow us to represent numbers from 4000 to 5000; MT = 4000 for example.


Code:

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);
Jermainejerman answered 2/5, 2016 at 21:4 Comment(0)
F
9

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
                    ["","X","XX","XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"],   // Tens
                    ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"]];        // Hundreds

function convert(num) {
  var numeral = "";
  var digits = num.toString().split('').reverse();
  for (var i=0; i < digits.length; i++){
    numeral = numeralCodes[i][parseInt(digits[i])] + numeral;
  }
  return numeral;  
}
<input id="text-input" type="text">
<button id="convert-button" onClick="var n = parseInt(document.getElementById('text-input').value);document.getElementById('text-output').value = convert(n);">Convert!</button>
<input id="text-output" style="display:block" type="text">
Floristic answered 21/8, 2015 at 21:3 Comment(0)
R
7

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;
}
Rainproof answered 4/6, 2019 at 13:10 Comment(0)
K
7

I created two convert functions.

The first function can convert numbers to roman using reduce. And the second function is very similar to the first function, the function uses the same way to convert the value.

Everything that you need to change is the _roman property. Because you have to extend this const with scale what you want, I place there max number 1000 but you can put more.

Larger scale with roman numbers you can find here https://www.tuomas.salste.net/doc/roman/numeri-romani.html

const _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 };

// 1903 => MCMIII
function toRoman(number = 0) {
    return Object.keys(_roman).reduce((acc, key) => {
        while (number >= _roman[key]) {
            acc += key;
            number -= _roman[key];
        }
        return acc;
    }, '');
}


// MCMIII => 1903
function fromRoman(roman = '') {
    return Object.keys(_roman).reduce((acc, key) => {
        while (roman.indexOf(key) === 0) {
            acc += _roman[key];
            roman = roman.substr(key.length);
        }
        return acc;
    }, 0);
}

console.log(toRoman(1903));  // should return 'MCMIII
console.log(fromRoman('MCMIII')); // should return 1903
Koan answered 25/1, 2022 at 7:9 Comment(0)
B
6

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
Basketwork answered 27/11, 2020 at 2:3 Comment(0)
S
5

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

Spile answered 31/1, 2012 at 16:26 Comment(0)
W
4

I created two twin arrays one with arabic numbers the other with the roman characters.

function convert(num) {

  var result = '';
  var rom = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
  var ara = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];

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++) {
    while (num >= ara[x]) {
      result += rom[x];
      num -= ara[x];
    }
  }
  return result;
}
Welloiled answered 1/8, 2015 at 12:46 Comment(0)
A
3

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 overlines so, you would need to use some trick to represent that, maybe a DIV with border-top, or some background image with those two overlines... 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;
}
Apnea answered 14/1, 2013 at 21:16 Comment(1)
I've edited this code to allow for numbers greater than 3,999,999. It may produce incorrect results, though, so use with caution. jsfiddle.net/DJDavid98/d2VEyCoterminous
K
3

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"];
        rnumbers = rnumbers.concat(["V","X","L","C","D","M"].map(function(n) {return '<span style="border-top:1px solid black; padding:1px;">'+n+'</span> '}));
        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> '}));
        rnumbers = rnumbers.concat(["V","X","L","C","D","M"].map(function(n) {return '<span style="border-top:3px double black; padding:1px;">'+n+'</span> '}));


    String.prototype.repeat = function( num ) {
        return new Array( num + 1 ).join( this );
    };

    function toRoman(n) {

        if(!n) return "";

        var strn = new String(n);
        var strnlength = strn.length;
        var ret = "";
        for(var i = 0 ; i < strnlength; i++) {
            var index = strnlength*2 -2 - i*2;
            var str;
            var m = +strn[i];
            if(index > rnumbers.length -1) {
                str = rnumbers[rnumbers.length-1].repeat(m*Math.pow(10,Math.ceil((index-rnumbers.length)/2)));
            }else {
                str = rnumbers[index].repeat(m);
                if (rnumbers.length >= index + 2) {
                    var rnregexp = rnumbers[index]
                            .split("(").join('\\(')
                            .split(")").join('\\)');
                    
                    str = str.replace(new RegExp('(' + rnregexp + '){9}'), rnumbers[index] + rnumbers[index + 2])
                            .replace(new RegExp('(' + rnregexp + '){5}'), rnumbers[index + 1])
                            .replace(new RegExp('(' + rnregexp + '){4}'), rnumbers[index] + rnumbers[index + 1])
                }
            }
            ret +=str;
        }

        return ret;
    }
    
<input type="text" value="" onkeyup="document.getElementById('result').innerHTML = toRoman(this.value)"/>

<br/><br/>

<div id="result"></div>
Kaiser answered 1/8, 2015 at 17:8 Comment(0)
C
3

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;
}
Caterwaul answered 21/6, 2016 at 7:55 Comment(0)
P
3
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));
Phenylketonuria answered 19/11, 2018 at 10:18 Comment(2)
Please explain your solutionSinecure
lets take 1012 so it is not equal to any key and also bigger than 1000 which is my first key so it will enter in 2nd if condition after that it will find the quotient which will be 1 so it will take result and add M*1 to it so now the result variable will have M in it and the num will be 12. So now 12>10 again it will enter and do the same thing so now result will become MX and num = 2 and again 2>1 so it will add MXI and now the num = 1. So now it will enter the first if condition andmake result = MXII.Phenylketonuria
S
3

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];
var romanNumeralGenerator = function (number) {
    return 'I'
        .repeat(number)
        .replace(/I{5}/g, 'V')
        .replace(/V{2}/g, 'X')
        .replace(/X{5}/g, 'L')
        .replace(/L{2}/g, 'C')
        .replace(/C{5}/g, 'D')
        .replace(/D{2}/g, 'M')
        .replace(/DC{4}/g, 'CM')
        .replace(/C{4}/g, 'CD')
        .replace(/LX{4}/g, 'XC')
        .replace(/X{4}/g, 'XL')
        .replace(/VI{4}/g, 'IX')
        .replace(/I{4}/g, 'IV')
};

console.log(numbers.map(romanNumeralGenerator))
Spam answered 8/10, 2019 at 11:4 Comment(0)
M
2

IF this number in HTMLElement (such as span), we recommend to Add HTML attribute data-format :

Number.prototype.toRoman = function() {
  var e = Math.floor(this),
    t, n = "",
    i = 3999,
    s = 0;
  v = [1e3, 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"];
  if (e < 1 || e > i) return "";
  while (s < 13) {
    t = v[s];
    while (e >= t) {
      e -= t;
      n += r[s]
    }
    if (e == 0) return n;
    ++s
  }
  return ""
};
var fnrom = function(e) {
  if (parseInt(e.innerHTML)) {
    e.innerHTML = parseInt(e.innerHTML).toRoman()
  }
};
setTimeout(function() {
  [].forEach.call(document.querySelectorAll("[data-format=roman]"), fnrom)
}, 10)
Phase <span data-format="roman">4</span> Sales
Mastoidectomy answered 30/11, 2014 at 10:38 Comment(0)
S
2

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){
  var d=0,o="",v,k="IVXLCDM".split("");
                    
  while(n!=0){
    v=n%10,x=k[d],y=k[d+1],z=k[d+2];
    o=["",x,x+x,x+x+x,x+y,y,y+x,y+x+x,y+x+x+x,x+z][v]+o;
    n=(n-v)/10,d+=2;
  }
  
  return o
}

var out = "";

for (var i = 0; i < 100; i++) {
  out += toRoman(i) + "\n";
}

document.getElementById("output").innerHTML = out;
<pre id="output"></pre>
Sexpartite answered 28/9, 2015 at 11:53 Comment(0)
M
2

function convertToRoman(num) {

  var romans = {
    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'
  };
  var popped, rem, roman = '',
    keys = Object.keys(romans);
  while (num > 0) {
    popped = keys.pop();
    m = Math.floor(num / popped);
    num = num % popped;
    console.log('popped:', popped, ' m:', m, ' num:', num, ' roman:', roman);
    while (m-- > 0) {
      roman += romans[popped];
    }
    while (num / popped === 0) {
      popped = keys.pop();
      delete romans[popped];
    }
  }
  return roman;
}
var result = convertToRoman(3999);
console.log(result);
document.getElementById('roman').innerHTML = 'Roman: ' + result;
p {
  color: darkblue;
}
<p>Decimal: 3999</p>
<p id="roman">Roman:</p>
Mossbunker answered 10/8, 2016 at 23:26 Comment(0)
U
2

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;
}
Uncanonical answered 1/11, 2016 at 0:26 Comment(0)
E
2

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;
}
Epiphragm answered 20/4, 2018 at 16:32 Comment(1)
That's the opposite from what is asked here.Vortumnus
G
2

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));
Gracegraceful answered 13/10, 2018 at 1:55 Comment(0)
H
2

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

  return result;
}
High answered 8/10, 2022 at 8:49 Comment(0)
C
1
/*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
Cavort answered 14/7, 2015 at 19:45 Comment(2)
Welcome to stackoverflow, please write what you did in the answer, and not just code: meta.stackexchange.com/questions/148272/…Additament
THis is the pi-iest post here. #31415926: https://mcmap.net/q/217623/-convert-a-number-into-a-roman-numeral-in-javascript :)Brinkley
P
1
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]);        
        }
    }
}
Pungy answered 28/9, 2015 at 18:32 Comment(0)
P
1

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;
}
Precipitous answered 12/2, 2016 at 17:48 Comment(0)
I
1

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);
Ionization answered 7/4, 2016 at 13:2 Comment(0)
O
1
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;
}
Oceania answered 31/8, 2016 at 22:19 Comment(0)
S
1
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);
Silicosis answered 21/9, 2016 at 18:55 Comment(0)
S
1
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;
}
Sprit answered 7/10, 2016 at 13:37 Comment(0)
O
1

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);
Oxalate answered 17/1, 2017 at 12:1 Comment(2)
This is way to big and overcomplicatedCassiecassil
Thanks for the feedback, you are absolutely right! I made it a week ago, now I refactord it a bit.Oxalate
S
1

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;
}
Suez answered 14/3, 2017 at 13:32 Comment(0)
G
1

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,
ol.roman-uppercase {
  display: inline-flex;
  margin: 0;
  padding: 0;
}

ol.roman-lowercase {
  list-style: lower-roman inside;
}

ol.roman-uppercase {
  list-style: upper-roman inside;
}
<ol class="roman-lowercase"><li value="4"></li></ol> <!-- iv. -->
<ol class="roman-uppercase"><li value="142"></li></ol> <!-- CXLII. -->
Gatha answered 5/6, 2017 at 15:45 Comment(0)
M
1

function convertToRoman(num) {
    var arr = [];
    for (var i = 0; i < num.toString().length; i++) {
        arr.push(Number(num.toString().substr(i, 1)));
    }
    var romanArr = [
        ["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"],
        ["M"]
    ];
    var roman = arr.reverse().map(function (val, i) {
        if (val === 0) {
            return "";
        }
        if (i === 3) {
            var r = "";
            for (var j = 0; j < val; j++) {
                r += romanArr[i][0];
            }
            return r;
        } else {
            return romanArr[i][val - 1];
        }
    });
    console.log(roman.reverse().join(""));
    return roman.join("");
}


convertToRoman(10);
Medallist answered 12/12, 2017 at 3:30 Comment(1)
Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others.Yaupon
O
1

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;
 };
Olli answered 29/8, 2018 at 5:48 Comment(0)
M
1

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;
}
Mccune answered 16/9, 2018 at 1:6 Comment(0)
T
1

Here is my code,Hope this helpful:

function convertToRoman(num) {
    let numArr = [];//[M,D,C,L,X,V,I]
    let numStr = "";

    //get num Array
    numArr.push(parseInt(num / 1000));
    num %= 1000;
    numArr.push(parseInt(num / 500));
    num %= 500;
    numArr.push(parseInt(num / 100));
    num %= 100;
    numArr.push(parseInt(num / 50));
    num %= 50;
    numArr.push(parseInt(num / 10));
    num %= 10;
    numArr.push(parseInt(num / 5));
    num %= 5;
    numArr.push(num);

    //cancat num String
    for(let i = 0; i < numArr.length; i++) {
        switch(i) {
            case 0://M
                for(let j = 0; j < numArr[i]; j++) {
                    numStr = numStr.concat("M");
                }
                break;
            case 1://D
                switch(numArr[i]) {
                    case 0:
                        
                        break;
                    case 1:
                        if(numArr[i + 1] === 4) {
                            numStr = numStr.concat("CM");
                            i++;
                        }else {
                            numStr = numStr.concat("D");
                        }
                        break;
                }
                break;
            case 2://C
                switch(numArr[i]) {
                    case 0:
                        
                        break;
                    case 1:
                        numStr = numStr.concat("C");
                        break;
                    case 2:
                        numStr = numStr.concat("CC");
                        break;
                    case 3:
                        numStr = numStr.concat("CCC");
                        break;
                    case 4:
                        numStr = numStr.concat("CD");
                        break;
                }
                break;
            case 3://L
                switch(numArr[i]) {
                    case 0:
                        
                        break;
                    case 1:
                        if(numArr[i + 1] === 4) {
                            numStr = numStr.concat("XC");
                            i++;
                        }else {
                            numStr = numStr.concat("L");
                        }
                        break;
                }
                break;
            case 4://X
                switch(numArr[i]) {
                    case 0:
                        
                        break;
                    case 1:
                        numStr = numStr.concat("X");
                        break;
                    case 2:
                        numStr = numStr.concat("XX");
                        break;
                    case 3:
                        numStr = numStr.concat("XXX");
                        break;
                    case 4:
                        numStr = numStr.concat("XL");
                        break;
                }
                break;
            case 5://V
                switch(numArr[i]) {
                    case 0:
                        
                        break;
                    case 1:
                        if(numArr[i + 1] === 4) {
                            numStr = numStr.concat("IX");
                            i++;
                        }else {
                            numStr = numStr.concat("V");
                        }
                        break;
                }
                break;
            case 6://I
                switch(numArr[i]) {
                    case 0:
                        
                        break;
                    case 1:
                        numStr = numStr.concat("I");
                        break;
                    case 2:
                        numStr = numStr.concat("II");
                        break;
                    case 3:
                        numStr = numStr.concat("III");
                        break;
                    case 4:
                        numStr = numStr.concat("IV");
                        break;
                }
                break;
        }
    }
    console.log(numStr);
    return numStr;
}

convertToRoman(3999);
Traynor answered 24/10, 2018 at 2:29 Comment(0)
A
1

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);
Alliance answered 3/11, 2018 at 2:16 Comment(0)
H
1

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
Halicarnassus answered 20/1, 2019 at 22:15 Comment(0)
B
1

Here you go.

function check(digit, char1, char2, char3) {
  if(digit <=3) {
    return char1.repeat(digit)
  }if(digit == 4){
    return char1+char2
  }if(digit == 5) {
    return char2
  }if (digit > 5 && digit < 9) {
    return char2+char1.repeat(digit-5)
  }if(digit == 9) {
    return char1+char3
  }
}

function convertToRoman(num) {
  let result;
  let numList = String(num).split("").reverse()
  result = [check(parseInt(numList[0]), 'I', 'V', 'X'),check(parseInt(numList[1]), 'X', 'L', 'C'),check(parseInt(numList[2]), 'C', 'D', 'M'),'M'.repeat(parseInt(numList[3]))]

 return result.reverse().join('');
}

let res = convertToRoman(2);
console.log(res)
Brooklynese answered 21/5, 2021 at 11:32 Comment(0)
V
1

Recursive, adding 1 before conversion, and then subtracting 1 after:

const toRoman = (num, i="I", v="V", x="X", l="L", c="C", d="D", m="M") =>
    num ? toRoman(num/10|0, x, l, c, d, m, "?", "?", num%=10) +
          (i + ["",v,x][++num/5|0] + i.repeat(num%5)).replace(/^(.)(.*)\1/, "$2")
        : "";

console.log(toRoman(3999));
Vortumnus answered 26/9, 2021 at 12:13 Comment(0)
C
1

This is the simpler, and easiest way to do this that I found.

class RomanNumeral {
    constructor(value, symbol){
        this.value = value;
        this.symbol = symbol;
    }
}

const romanNumerals = [
    new RomanNumeral(1000, "M"),
    new RomanNumeral(900, "CM"),
    new RomanNumeral(500, "D"),
    new RomanNumeral(400, "CD"),
    new RomanNumeral(100, "C"),
    new RomanNumeral(90, "XC"),
    new RomanNumeral(50, "L"),
    new RomanNumeral(40, "XL"),
    new RomanNumeral(10, "X"),
    new RomanNumeral(9, "IX"),
    new RomanNumeral(5, "V"),
    new RomanNumeral(4, "IV"),
    new RomanNumeral(1, "I"),
];

function roman(number) {
    assertNumberInRomanLimits(number);
    let result = "";
    for (const { value , symbol  } of romanNumerals){
        while(number >= value){
            result += symbol;
            number -= value;
        }
    }
    return result;
}

function assertNumberInRomanLimits(number) {
    if (number > 3999) {
        throw new RangeError("The biggest number we can form in Roman numerals is MMMCMXCIX (3999).");
    }
    if (number < 1) {
        throw new RangeError("There is no concept of 0 or negatives in Roman numerals.");
    }
};

console.log(roman(3)); //=> "III"

console.log(roman(47)); //=> "XLVII"

console.log(roman(3990)); //=> "MMMCMXC"

console.log(roman(3999)); //=> "MMMCMXCIX"

console.log(roman(1984)); //=> "MCMLXXXIV"

If you would like to use this a module, you can 👇

https://github.com/UltiRequiem/roman.js

https://ulti.js.org/roman.js

It includes 100% code coverage, TypeScript Types, and Documentation.

Chute answered 13/6, 2022 at 20:21 Comment(0)
T
1

Just wanted to post my first comment on stackoverflow :)

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

  let romanConv = "";

  for (let i = 0; i < 4; i++) {
    for (let j = 0; j < romanNum[0].length; j++) {
      if (num >= romanNum[0][j] && num < romanNum[0][j + 1]) {
        let x = parseInt(num / romanNum[0][j]);
        romanConv += romanNum[1][j].repeat(x);
        num %= romanNum[0][j];
      }
    }
  }

  return romanConv;
}

console.log(convertToRoman(3999));
Trinee answered 13/9, 2022 at 11:6 Comment(0)
G
1
const romanSymbols = {
    '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 intToRoman = function(num) {
    if(isNaN(num)) return false;
    if(num==0) return '';

    for (let key in romanSymbols) {
        if(num >= romanSymbols[key] && num > 0) {
            num = num - romanSymbols[key];
            return result = key + intToRoman(num);
        }
    }
};

const romanToInt = function(roman) {
    if(!isNaN(roman)) return 0;
    if(roman=='' || roman=='undefined') return 0;

    for (let key in romanSymbols) {
        if(roman.indexOf(key)===0) {
            roman = roman.replace(key, '');
            return romanSymbols[key] + parseInt(romanToInt(roman));
        }
    }
};

const romanSymbols = {
    '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,
};

const intToRoman = function(num) {
    if(isNaN(num)) return false;
    if(num==0) return '';

    for (let key in romanSymbols) {
        if(num >= romanSymbols[key] && num > 0) {
            num = num - romanSymbols[key];
            return result = key + intToRoman(num);
        }
    }
};

const romanToInt = function(roman) {
    if(!isNaN(roman)) return 0;
    if(roman=='' || roman=='undefined') return 0;

    for (let key in romanSymbols) {
        if(roman.indexOf(key)===0) {
            roman = roman.replace(key, '');
            return romanSymbols[key] + parseInt(romanToInt(roman));
        }
    }
};

function convertRoman() {
    val = document.getElementById('textId').value;
    var resp = intToRoman(val)
    console.log('result:', resp);
}

function convertInt() {
    val = document.getElementById('textId').value;
    var resp = romanToInt(val)
    console.log('result:', resp);
}
<input id="textId" />
<button id="submitBtn" onclick="convertInt()">To Interger</button>
<button id="submitBtn" onclick="convertRoman()">To Roman</button>
Grandchild answered 8/11, 2023 at 17:28 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Tahr
G
0
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;
  }
};
Gamages answered 15/4, 2015 at 13:34 Comment(0)
M
0

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
}
Michaels answered 29/4, 2016 at 2:25 Comment(4)
an explanation of the code would raise the answer valueSpiritualist
Did you just post a copy of the jQuery library ;) took me a while to read this, might wanna simplify.Silicosis
Sorry guys, I just saw your comments. I 'll add comments to the code ASAPMichaels
Did it, I added some comments (although I am afraid I overdid it)Michaels
B
0

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.

Bouie answered 17/5, 2016 at 8:55 Comment(0)
E
0
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("");
}
Echolocation answered 30/6, 2016 at 17:9 Comment(0)
G
0

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('');
}
Gretchengrete answered 26/7, 2016 at 20:40 Comment(0)
D
0

Here is my "as functional as it gets" solution.

var numerals = ["I","V","X","L","C","D","M"],
      number = 1453,
      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]
      result = digits.reduce((p,c,i) => (c === 0 ? ""
                                                 : c < 4 ? numerals[2*i].repeat(c)
                                                         : c === 4 ? numerals[2*i] + numerals[2*i+1]
                                                                   : c < 9 ? numerals[2*i+1] + numerals[2*i].repeat(c-5)
                                                                           : numerals[2*i] + numerals[2*i+2]) + p,"");
console.log(result);
Danaus answered 30/7, 2016 at 17:12 Comment(0)
V
0
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 ''
}
Vitale answered 24/9, 2016 at 10:12 Comment(0)
P
0

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
function romannum(num,rnum1,rnum2,rnum3){
  var result = "";
  if(num >= 1 && num < 4){
    while(num>0){
      result += rnum1;
      num--;
    }
  }
  else if(num > 5 && num < 9){
    result = rnum2;
    while(num>5){
      result += rnum1;
      num--;
    }  
  }
  else if(num == 4){
    result += rnum1 + rnum2;
  }
  else if( num == 5){
    result += rnum2;
  }
  else if( num == 9){
    result += rnum1+ rnum3;
  }
  return result;
}
//the main function
function convertToRoman(num) {
 num = num.toString().split('');
 var length = num.length;
 var x = 0;
 var result =[];

 while((length - x) > 0){
   if(length -x === 4){
    result.push(romannum(num[x],"M","",""));
   }
   else if(length -x  === 3){
     result.push(romannum(num[x],"C","D","M"));
   }
   else if(length - x  === 2){
     result.push(romannum(num[x],"X","L","C"));
   }
   else if(length - x === 1){
     result.push(romannum(num[x],"I","V","X"));
   }
   x++;  
 }
Perseverance answered 25/11, 2016 at 16:35 Comment(0)
U
0

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;
}
Umont answered 10/1, 2017 at 10:55 Comment(0)
W
0

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('');
Walk answered 3/3, 2017 at 22:15 Comment(0)
A
0

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.

Aholah answered 18/5, 2017 at 2:48 Comment(0)
R
0

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;
}
Robinett answered 23/5, 2017 at 23:25 Comment(0)
D
0

const romanize = num => {
  const romans = {
    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 roman = '';
  
  for (let key in romans) {
    const times = Math.trunc(num / romans[key]);
    roman += key.repeat(times);
    num -= romans[key] * times;
  }

  return roman;
}

console.log(
  romanize(38)
)
Dacoit answered 10/7, 2017 at 23:5 Comment(0)
H
0

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

Harmonious answered 12/8, 2017 at 19:35 Comment(0)
T
0
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;
}
Though answered 14/9, 2017 at 14:58 Comment(0)
S
0

function convertToRoman(num) {
  var toTen = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"];
  var toHungred = ["", "X" ,"XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "C"];
  var toThousend = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "M"];  			
  var arrString = String(num).split("");  
  var arr = [];           
  if (arrString.length == 3 ){  				
  	  	arr.push(toThousend[arrString[+0]]);
  	  	arr.push(toHungred[arrString[+1]]);
  	  	arr.push(toTen[arrString[+2]]);
   } 
  else if (arrString.length == 2 ){  				
   	  arr.push(toHungred[arrString[+0]]);
  	  arr.push(toTen[arrString[+1]]);  			  	
  }
  else if (arrString.length == 1 ){  				
  	arr.push(toTen[arrString[+0]]);  			  	  	
  }
  else if (arrString.length == 4 ) {
    for (var i =1; i<=[arrString[+0]]; i++) {
                  arr.push("M");                  
                }
    arr.push(toThousend[arrString[+1]]);
  	arr.push(toHungred[arrString[+2]]);
  	arr.push(toTen[arrString[+3]]);
  }              
  console.log (arr.join(""));
}

convertToRoman(36);
Satiable answered 9/1, 2018 at 10:46 Comment(1)
you should add comments and explanationCharade
R
0

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
  rom=rom||''
  if(isNaN(val)||val==0) 
    return rom;
  for(i=0;curval=[1000,900,500,400,100,90,50,40,10,9,5,4,1][i],i<13;i++)
    if(val >= curval)
	   return numberToRoman(val-curval,rom+['M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'][i])
}

function romanToNumber(txtRom){//returns NaN if invalid string
  txtRom=txtRom.toUpperCase();
  if (!/^M*(CM|CD|(D?C{0,3}))?(XC|XL|(L?X{0,3}))?(IX|IV|(V?I{0,3}))?$/.test(txtRom))
    return NaN;
  var retval=0;
  txtRom.replace(/[MDLV]|C[MD]?|X[CL]?|I[XV]?/g, function(i) {
    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]; 
  });
  return retval;
}
#tblRoman{border-collapse:collapse;font-family:sans-serif;font-size:.8em}
<h3>Roman to Number Conversion</h3>
<input type="button" value="example 1" onclick="document.getElementById('romanval').value='mmmmmmmcdlxxxiv'">
<input type="button" value="example 2" onclick="document.getElementById('romanval').value='mmmmmmmdclxxxiv'">
<input type="button" value="example 3" onclick="document.getElementById('romanval').value='mmmmmmmdxcdlxxxiv'">
<p>
Enter a Roman Number below, or click on an example button. Then click Convert 
</p>
<input type="text" size="40" id="romanval">
 <input type="button" onclick="document.getElementById('resultval').innerText
 = romanToNumber(document.getElementById('romanval').value)" value="Convert"> 
<p />
Numeric Value: <b id="resultval"></b>

<hr>
<h3>Number to Roman Conversion</h3>
<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>'">

<table id="tblRoman" border></table>
Ruben answered 24/4, 2018 at 20:52 Comment(0)
A
0

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);
}
Applecart answered 29/4, 2018 at 0:1 Comment(0)
L
0

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('');
}
Landpoor answered 28/6, 2018 at 19:43 Comment(0)
L
0

const basicRomanNumeral = 
  ['',
    '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','',
    'M','MM','MMM'
  ];

function convertToRoman(num) {
  const numArray = num.toString().split('');
  const base = numArray.length;
  let count = base-1;
  const convertedRoman = numArray.reduce((roman, digit) => {
    const digitRoman = basicRomanNumeral[+digit + count*10];
    const result = roman + digitRoman;
    count -= 1;
    return result;
  },'');
  return convertedRoman;
}
Lurlinelusa answered 19/8, 2019 at 8:38 Comment(0)
P
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

Proleg answered 19/9, 2019 at 11:46 Comment(0)
U
0
    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)

};
Ugh answered 12/10, 2019 at 16:53 Comment(0)
C
0

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
Confined answered 22/10, 2019 at 18:3 Comment(0)
P
0

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
    const arabic_benchmarks = Object.keys(roman_benchmarks);

    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;
}


Paley answered 2/4, 2020 at 6:13 Comment(0)
A
0
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;
}
Abell answered 3/7, 2020 at 20:0 Comment(0)
S
0

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);    }
Southwick answered 28/9, 2020 at 16:20 Comment(0)
O
0

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); 
Oratory answered 21/12, 2020 at 8:50 Comment(0)
A
0
function convertToRoman(num) {

    let I = 1
    let IV = 4
    let V = 5
    let IX = 9
    let X = 10
    let XL = 40
    let L = 50
    let XC = 90
    let C = 100
    let CD = 400
    let D = 500
    let CM = 900
    let M = 1000

    let arr = []
    while(num > 0) {
        console.log(num)
        switch(true) {

            case num - M >= 0 :
                arr.push('M')
                num -= M
                break
            case num - CM >= 0 :
                arr.push('CM')
                num -= CM
                break
            case num - D >= 0 :
                arr.push('D')
                num -= D
                break
            case num - CD >= 0 :
                arr.push('CD')
                num -= CD
                break
            case num - C >= 0 :
                arr.push('C')
                num -= C
                break
            case num - XC >= 0 :
                arr.push('XC')
                num -= XC
                break
            case num - L >= 0 :
                arr.push('L')
                num -= L
                break
            case num - XL >= 0 :
                arr.push('XL')
                num -= XL
                break
            case num - X >= 0 :
                arr.push('X')
                num -= X
                break
            case num - IX >= 0 :
                arr.push('IX')
                num -= IX
                break
            case num - V >= 0 :
                arr.push('V')
                num -= V
                break
            case num - IV >= 0 :
                arr.push('IV')
                num -= IV
                break
            case (num - I) >= 0 :
                arr.push('I')
                num -= I
                break
        }
    }

    str = arr.join("")

    return str
}
Appreciate answered 11/3, 2021 at 4:30 Comment(2)
Please add a little description about the code you have added. It will help the reader to understand it better.Edelmiraedelson
Problem from FCC Med. JS Scripting. Answer features a switch statement nested inside a while loop. Originally stuck, breakthrough came from adding variables for 4th and 9th for numbers in tenths, hundredths, thousandths. So IV for 4, IX, 9, XL, 40Appreciate
S
0
function convertToRoman(num: number){
  let integerToRomanMap = new Map<number, string>([
    [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"]
  ])
  if(integerToRomanMap.has(num)){
    return integerToRomanMap.get(num)
  }
  let res = ''
  while(num > 0){
    let len = String(num).length;
    let divisor = Math.pow(10, len - 1)
    let quotient = Math.floor(num/divisor)
    num = num % divisor
    if(integerToRomanMap.has(divisor * quotient)){
      res += integerToRomanMap.get(divisor * quotient)
    }else{
      while(quotient > 0){
        res += integerToRomanMap.get(divisor)
        quotient--;
      }
    }
  }
  return res;
}
Spleenwort answered 8/5, 2021 at 16:0 Comment(0)
C
0

Just to add big number if anybody needs it

function convertToRoman(num) {

if (num < 1 ) {
    console.error('Error (fn convertToRoman(num)): Can\'t convert negetive numbers. You provided: ' + num);
    return false;
}
if (+num > 3000000) {
    console.error('Error (fn convertToRoman(num)): Can\'t convert numbers greater than 3000000. 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;
}

function num2let(a, b, c, num) {
    if(num < 4) return a.repeat(num);
    else if (num === 4) return a + b;
    else if (num < 9) return b + a.repeat(num - 5);
    else return a + c;
}

let romanArray = ["I", "V", "X", "L", "C", "D", "M", "Vb", "Xb", "Lb", "Cb", "Db", "Mb"]; // Xb means Xbar

let arr = String(+num).split('').map(el => +el);
let len = arr.length;
let roman = "";
arr.forEach(el => {
    let index = (len - 1) * 2;
    roman += num2let(romanArray[index], romanArray[index  + 1], romanArray[index + 2], el);
    len--;
});

return roman;
}
Cleistogamy answered 22/5, 2021 at 20:35 Comment(0)
I
0

var intToRoman = function(value) {
    const romanObj = {
        1: 'I',
        2: 'II',
        3: 'III',
        4: 'IV',
        5: 'V',
        6: 'VI',
        7: 'VII',
        8: 'VIII',
        9: 'IX',
        10: 'X',
        40: 'XL',
        50: 'L',
        60:'LX',
        70: 'LXX',
        80:'LXXX',
        90: 'XC',
        100: 'C',
        400: 'CD',
        500: 'D',
        600: 'DC',
        700:'DCC',
        800:'DCCC',
        900: 'CM',
        1000:'M'
    };
    let romanValue = '';
    while(value>0){
        let x = value.toString().length - 1;
        let y = x == 0 ? 0 : 10 ** x;
        if(!y) { romanValue += romanObj[value], value=0; }
        else {
            
            let temp = value % y;
            let multiple = Math.floor(value/y);
            if (romanObj[multiple*y]) {
                romanValue+=romanObj[multiple*y];
            } else {
                console.log('logger of 1996', romanObj[y], y);
                romanValue+=romanObj[y].repeat(multiple);
            }
            value=temp;
        }
    }
    return romanValue;
}

console.log(intToRoman(18))
Implosion answered 6/6, 2021 at 19:48 Comment(0)
M
0

It works from 1 t0 9999. if perchance there is a roman figure for 10000, just replace it with the roman figure and create another limit of 99999.

function convertToRoman(num) {
  const numArray = num.toString().split("")
  const roman = {
    1: "I",
    5: 'V',
    10: 'X',
    50: 'L',
    100: 'C',
    500: "D",
    1000: 'M',
    9999: "LIMIT"
  }

  let numLen = numArray.length;
  let converted = numArray.map((x) => {
    numLen--;
    return x + "0".repeat(numLen)
  })

  let trans = converted.map((x) => {
    let last = "";

    for (let key in roman) {
      if (x.charAt(0) == 0) {
        return ""
      }

      if (key == x) {
        return roman[key];
      }

      if (key > parseInt(x) && last < parseInt(x)) {
        if (last.length == key.length) {
          const ave = (parseInt(last) + parseInt(key)) / 2

          if (x > ave) {
            return roman[last] + roman[key]
          }

          return roman[last].repeat(x.charAt(0));
        }

        if (x.charAt(0) == 9) {
          return roman[key.slice(0, key.length - 1)] + roman[key];
        }

        return roman[last] + roman[key.slice(0, key.length - 1)].repeat(x.charAt(0) - 5)
      }

      last = key
    }
  })

  return trans.join("");
}

for(let i = 1; i < 12; i++) {
    console.log(i, "->", convertToRoman(i))
}
Modality answered 11/7, 2021 at 16:15 Comment(0)
C
0

Candy from a baby.

At first you have to map romam to cardinal numbers in a object:

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

/* The CM, CD, XC, XL, IX and IV properties are
only needed for the cardinalToRoman() function below. */

Note: If you just need to convert roman to cardinal, so you will don't need the properties with two romans chars in the object above.

Then you build a function to do the magic conversion of cardinal to roman numbers:

// The funciton receives a cardinal as parameter (of integer type)
const cardinalToRoman = num => {

    // M is the last char in the roman numeric system. Just preventing crashes.
    if (num >= 4000) {
        console.log('Number is too big'); 
        return
    }

    let roman = ''; // The initial roman string

    // It iterates over the _numbersMap object's properties
    for (var i of Object.keys(_numbersMap)) {

        /* For each iteration, it will calculate the division of the
        given number by the value of the property beeing iterated. */
        var q = Math.floor(num / _numbersMap[i]);

        /* So the value, multiplied by the current property's value,
        will be subtracted from the given number */
        num -= q * _numbersMap[i]; 

        /* The result will be the times that the key of the
        current property (its respective roman sting) will be repeated
        in the final string */
        roman += i.repeat(q); 
    }

    return roman;
};

And finally if you want to make the inverse, then build a function to convert roman to cardinal integers:

// The funciton receives a roman number as parameter (of srting type)
const romanToCardinal = roman => {

    let num = 0; // Initial integer number
    
    /* Let's split the roman string in a Array of chars, and then
    put it in reverse order */
    const romansArray = Array.from(roman).reverse();
    
    // Then let's iterate the array
    romansArray.forEach((char, index, array) => {
            
        /* We take the integer number corresponding to the current
        and the previous chars in the iteration. */
        const currentNumChar = _numbersMap[char];
        const prevNumChar = _numbersMap[array[index - 1]];
        
        // Throws error if the char is unknown.
        if (!currentNumChar) {
            console.error(`The charecter "${char}" of the given roman number "${roman}" is invalid as a roman number char.`);
            return false;
        }
        
        /* The integer corresponding to the current char is 
        subtracted from the result if it's bigger than the previous
        integer. If itsn't, the integer is summed to the result */
        if (prevNumChar && prevNumChar > currentNumChar) {
            num -= currentNumChar;
        } else {
            num += currentNumChar;
        }
        
    });
    
    return num;
}

Try it on JSFiddle.

Canaigre answered 16/8, 2021 at 19:30 Comment(1)
Please try to give proper explanation of the answer.Spiderwort
W
0
let converter={
 I : 1, II: 2, III:3, IV:4, V:5, VI:6, VII:7, VIII:8, IX:9
 }
 let converter1={
    X:10,XX:20,XXX:30,XL:40,L:50,LX:60,LXX:70,LXXX:80,XC:90
 }
 let converter2={
    C:100,CC:200,CCC:300,CD:400,D:500,DC:600,DCC:700,DCCC:800,CM:900
 }

    let result= []
  function convertToRoman(number){

        if(number >= 1000){
                  let l = 'M'
                  result.push(l.repeat(number/1000))
                    if(number%1000  < 1000){
                    number = number%1000
                  }
                }
           if(100 <=number && number <= 999){
                      let border = String(number)[0]
                      for(let i=0; i <= Number(border); i++){
                        if(Object.values(converter2)[i]/ Number(border) == 100){
                          result.push(Object.keys(converter2)[i])
                          number = number-Object.values(converter2)[i]

                        }
                        }
                    }
    if(10 <= number && number <= 99){

                      let border= String(number)[0]

                      for(let i = 0; i < Number(border) ; i++){
                        if(Object.values(converter1)[i]===  Number(border)*10  ){
                          result.push(Object.keys(converter1)[i])
                            number = number-Object.values(converter1)[i]
                          }
                        }
                }

    if(number <= 9){
                    for(let i = 0; i <= number; i++){
                      if(Object.values(converter)[i] == number){
                        result.push(Object.keys(converter)[i])
                        result = result.join("")
                          result = String(result)
                        return result
                            }
                                }
                    }
                    result = result.join("")
                      result = String(result)
                    return result
                }


console.log(convertToRoman(9))
Willhite answered 25/2, 2022 at 19:10 Comment(0)
T
0

I feel this solution might help you get a better understanding of the problem

const romanNumeral = function (num) {
let roman = "";
let nums = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
let romans = [
"M",
"CM",
"D",
"CD",
"C",
"XC",
"L",
"XL",
"X",
"IX",
"V",
"IV",
"I",
];
for (let i = 0; i < nums.length; i++) {
while (num >= nums[i]) {
  roman += romans[i];
  num -= nums[i];
}
return roman;
};
Ton answered 19/3, 2022 at 19:27 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Tahr
W
0

In simple way -

function convertToRoman (num) {
  const romanList = {
    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 roman = "";
  Object.keys(romanList).forEach((key, index) => {
      let temp = parseInt(num / romanList[key]);
      num = num % romanList[key];
      roman = roman + key.repeat(temp);
  });

  return roman;
};
Willenewillet answered 15/4, 2022 at 14:15 Comment(0)
H
0

A non-recursive no-loop solution with nested curried functions for fun:

const convert =
  (base, sym, next) =>
    (num, res = '') =>
      next && num
        ? next(num % base, res + sym.repeat(num / base))
        : res + sym.repeat(num);

const roman = convert(1000,  'M',
              convert( 900, 'CM',
              convert( 500,  'D',
              convert( 400, 'CD',
              convert( 100,  'C',
              convert(  90, 'XC',
              convert(  50,  'L',
              convert(  40, 'XL',
              convert(  10,  'X',
              convert(   9, 'IX',
              convert(   5,  'V',
              convert(   4, 'IV',
              convert(   1,  'I')))))))))))));

roman(1999); //> 'MCMXCIX'

How does it work?

We define a convert function that takes a base number (base), its Roman numeral (sym) and an optional next function that we use for the next conversion. It then returns a function that takes a number (num) to convert and an optional string (res) used to accumulate previous conversions.

Example:

const roman =
  convert(1000, 'M', (num, res) => console.log(`num=${num}, res=${res}`));
//        ^^^^  ^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//        base  sym  next

roman(3999);
// LOG: num=999, res=MMM

Note that roman is the function returned by convert: it takes a number (num) and an optional string res. It is the same signature as the next function…

This means we can use the function returned by convert as a next function!

const roman =
  convert(1000, 'M',
    convert(900, 'CM', (num, res) => console.log(`num=${num}, res=${res}`)));

roman(3999);
// LOG: num=99, res=MMMCM

So we can keep nesting convert functions to cover the entire Roman numerals conversion table:

const roman =
  convert(1000,  'M',
    convert( 900, 'CM',
      convert( 500,  'D',
        convert( 400, 'CD',
          convert( 100,  'C',
            convert(  90, 'XC',
              convert(  50,  'L',
                convert(  40, 'XL',
                  convert(  10,  'X',
                    convert(   9, 'IX',
                      convert(   5,  'V',
                        convert(   4, 'IV',
                          convert(   1,  'I')))))))))))));

When next is not defined it means that we reached the end of the conversion table: convert(1, 'I') which is as simple as repeating 'I' n times e.g. 3 -> 'I'.repeat(3) -> 'III'.

The num check is an early exit condition for when there is nothing left to convert e.g. 3000 -> MMM.

Hwang answered 19/4, 2022 at 22:41 Comment(0)
J
0

didn't see a matrix array being used together with a for and a nested ternary operator, looks fancy but it's barely out of the hard-code zone, hope you like it!.

function rome(num) {
  if (num > 3999) {return 'number too large'};
  let strNum = JSON.stringify(num).split("");
  let number = [];
  let romans = [ ['I','IV','V','IX'],
                 ['X','XL','L','XC'],
                 ['C','CD','D','CM'],
                 ['M','','','']      ]; 
  for (let j = strNum.length - 1 ; 0 <= j; j--){
      let digit ='';
      digit = strNum[j] == 0 ?  '' : 
              strNum[j] <= 3 ? 
              romans[strNum.length-1-j][0].repeat(Number(strNum[j])) :
              strNum[j] == 4 ? romans[strNum.length-1-j][1] : 
              strNum[j] == 5 ? romans[strNum.length-1-j][2] :
              strNum[j] <= 8 ? romans[strNum.length-1-j][2] + 
              romans[strNum.length-1-j][0].repeat(Number(strNum[j])-5) : 
              romans[strNum.length-1-j][3] ;
      number.unshift(digit);
      };
  return ''.concat(number.join(''));
 }
Jambeau answered 30/4, 2022 at 0:53 Comment(0)
E
0

This is how I solved it. The logic is that roman numbers follow a rule from 1 to 9 and only changes the letters depending of the index of the number.

function convertToRoman(num) {
  const roman = {1: 'I', 2: 'II', 3: 'III', 4: 'IV', 5: 'V', 6: 'VI', 7: 'VII', 8: 'VIII', 9: 'IX'}
  
  return num
    .toString()
    .split('')
    .reverse()
    .map((n, i) => 
      (i == 0) ? roman[n] : 
      (i == 1 && n != 0) ? 
        roman[n]
          .split('')
          .map(a => 
               (a == 'I') ? 'X' :
               (a == 'V') ? 'L' :
               (a == 'X') ? 'C' : '')
          .join('') :
      (i == 2 && n != 0) ?
        roman[n]
          .split('')
          .map(a => 
               (a == 'I') ? 'C' :
               (a == 'V')  ? 'D' :
               (a == 'X')  ? 'M' : '')
          .join('') :
      (i == 3 && n != 0) ?
        roman[n]
          .split('')
          .map(a => a == 'I' ? 'M' : '')
          .join('') : '')
    .reverse()
    .join('')
}
Empurple answered 19/5, 2022 at 22:2 Comment(0)
D
0

I think my answer is a conceptual method for learning and it is clear why this happens

var initialValue = {
  I: 1,
  V: 5,
  X: 10,
  L: 50,
  C: 100,
  D: 500,
  M: 1000
};

var romanToInt = function (s) {
  let defaultNumber = 0;
  for (let i = 0; i < s.length; i++) {
    if (s[i] === "I" && s[i + 1] === "V") {
      return (defaultNumber += 4);
      i++;
    } else if (s[i] === "I" && s[i + 1] === "I" && s[i + 2] === "I") {
      return (defaultNumber += 3);
      i++;
    } else if (s[i] === "I" && s[i + 1] === "I") {
      return (defaultNumber += 2);
      i++;
    } else if (s[i] === "I" && s[i + 1] === "X") {
      return (defaultNumber += 9);
      i++;
    } else if (s[i] === "C" && s[i + 1] === "M") {
      defaultNumber += 900;
      i++;
    } else if (s[i] === "X" && s[i + 1] === "C") {
      defaultNumber += 90;
      i++;
    } else if (s[i] === "C" && s[i + 1] === "D") {
      defaultNumber += 400;
      i++;
    } else if (s[i] === "X" && s[i + 1] === "L") {
      defaultNumber += 40;
      i++;
    } else {
      defaultNumber += initialValue[s[i]];
    }
  }

  return defaultNumber;
};

romanToInt("MCMXCIV");
Dee answered 21/9, 2022 at 8:11 Comment(0)
I
0

So this is my answer to the problem:

const key1 = ["I", "IV", "V", "IX"];
const key2 = ["X", "XL", "L", "XC"];
const key3 = ["C", "CD", "D", "CM"];
const key4 = ["M"];
const keys = [key1, key2, key3, key4];

function convertToRoman(num) {
    const numArray = Array.from(String(num)).reverse();

    let arr = numArray.map((el, i) => {
        let rom = [];

        if (el <= 3) {
            for (let t = 1; t <= el; t++) {
                rom.push(keys[i][0]);
            }
        } else if (el == 4) {
            rom.push(keys[i][1]);
        } else if (el >= 5 && el < 9) {
            rom.push(keys[i][2]);
            if (el > 5) {
                let dif = el - 5;
                for (let t = 1; t <= dif; t++) {
                    rom.push(keys[i][0]);
                }
            }
        } else rom.push(keys[i][3]);

        return rom.flat().join("");
    });
    res = arr.reverse().flat().join("");
    console.log(res);
    return res;
    }
    
    convertToRoman(365);
Israelite answered 3/10, 2022 at 20:26 Comment(0)
D
0

I know that no one really needs another example here, but I wanted to add one that's simple to read and doesn't special-case anything. Instead my code treats every power of 10 in turn, and within each, can go into "debt", to handle the subtractive notation.

// For each power of 10, we break down the number
// and build up the roman numeral characters
function convertToRoman(num) {
    let roman = [];
    [roman, num] = convertPowerOfTen(roman, num, 1000, "M");
    [roman, num] = convertPowerOfTen(roman, num, 100, "C", "D");
    [roman, num] = convertPowerOfTen(roman, num, 10, "X", "L");
    [roman, num] = convertPowerOfTen(roman, num, 1, "I", "V");
    return roman.join("");
}

function convertPowerOfTen(roman, num, multiplier, unitChar, fiveChar) {
    // Handle multiple of 5, possibly going into "debt"
    if (num >= 4 * multiplier) {
        roman.push(fiveChar);
        num -= 5 * multiplier;
    }
    // If in debt, insert unit character before the last one
    if (num <= -1) {
        roman.splice(-1, 0, unitChar)
        num += multiplier;
    }
    // Insert as many unit characters as needed
    while (num >= multiplier * 0.9) {
        roman.push(unitChar);
        num -= multiplier;
    }
    return [roman, num];
}
Dowable answered 8/11, 2022 at 14:10 Comment(0)
S
0

As a noob this was my answer to this question:

function convertToRoman(num, answer = []) {
 if (num >= 1000) {
   answer.push('M')
   return convertToRoman(num - 1000, [...answer])
 }
 if (num >= 900) {
   answer.push('CM')
   return convertToRoman(num - 900,  [...answer])
 }
 if (num >= 500) {
   answer.push('D')
   return convertToRoman(num - 500,  [...answer])
 }
 if (num >= 400) {
   answer.push('CD')
   return convertToRoman(num - 400,  [...answer])
 }
 if (num >= 100) {
   answer.push('C')
   return convertToRoman(num - 100,  [...answer])
 }
 if (num >= 90) {
   answer.push('XC')
   return convertToRoman(num - 90,  [...answer])
 }
 if (num >= 50) {
   answer.push('L')
   return convertToRoman(num - 50,  [...answer])
 }
 if (num >= 40) {
   answer.push('XL')
   return convertToRoman(num - 40, [...answer])
 }
 if (num >= 10) {
   answer.push('X')
   return convertToRoman(num - 10,  [...answer])
 }
 if (num >= 9) {
   answer.push('IX')
   return convertToRoman(num - 9,  [...answer])
 }
 if (num >= 5) {
   answer.push('V')
   return convertToRoman(num - 5,  [...answer])
 }
 if (num >= 4) {
   answer.push('IV')
   return convertToRoman(num - 4,  [...answer])
 }
 if (num >= 1) {
   answer.push('I')
   return convertToRoman(num - 1,  [...answer])
 }
  return answer.join('');
}
Substituent answered 21/11, 2022 at 21:44 Comment(0)
P
0

I came up with this solution:

function toRoman(str) {
    const g = [
        ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
        ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'LC'],
        ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'],
        ['', 'M', 'MM', 'MMM','MMMM','V\u0305','V\u0305M','V\u0305MM','V\u0305MMM','MX\u0305']
    ]
    a = str.toString()
    console.assert(a.length < 5, 'Number must be less than 10000 was %o', {a});
    return isNaN(a) ? NaN : [...a].map((s, i) => g[a.length - i - 1][s]).join("")
}

Features:

  1. It uses the efficient spread operator to iterate over a string.
  2. Works for numbers from 1 to 9999.
  3. Returns NaN if not a number.
  4. Throws an error if the number is > 9999.
  5. XI lines of code.
Publicize answered 13/12, 2022 at 13:48 Comment(0)
D
0

My Code

var romanToInt = function(s) {
const data = {
    I: 1,
    V: 5,
    X: 10,
    L: 50,
    C: 100,
    D: 500,
    M: 1000,
    CM: 900,
    CD: 400,
    IV: 4,
    IX: 9,
    XL: 40,
    XC: 90
};

let returned = 0;
let previousLetter = false;
for(let i = 0; i < s.length; i++) {
    let letter = s[i];
    let value = 0;
    if(!previousLetter) {
        const nextLetter = s[i + 1];
        const compareLetter = letter + nextLetter;
        if(compareLetter === 'CM' || compareLetter === 'CD' || compareLetter === 'IV' || compareLetter === 'IX' || compareLetter === 'XL' || compareLetter === 'XC') {
            value = data[compareLetter]
            previousLetter = true;
            console.log(compareLetter, value)
        }else {
            value = data[letter]
            console.log(letter, value)
        }
        returned = returned + value
    }else {
        previousLetter = false;
    }
}

console.log('RETURN', returned)

return returned};
Desjardins answered 9/5, 2023 at 14:55 Comment(0)
D
0

This might be helpful..

 let num = 58;
    console.log("ans: ", integerToRomanOptimal(num));
    
    function integerToRomanNaive(num) {
      let map = new Map();
      map.set(1, "I");
      map.set(5, "V");
      map.set(10, "X");
      map.set(50, "L");
      map.set(100, "C");
      map.set(500, "D");
      map.set(1000, "M");
    
      let base = 1;
      const result = [];
      while (num > 0) {
        const last = num % 10;
        if (last < 4) {
          for (let k = last; k > 0; k--) {
            result.unshift(map.get(base));
          }
        } else if (last == 4) {
          result.unshift(...[map.get(base), map.get(base * 5)]);
        } else if (last == 5) {
          result.unshift(map.get(base * 5));
        } else if (last < 9) {
          for (let k = last; k > 5; k--) {
            result.unshift(map.get(base));
          }
          result.unshift(map.get(base * 5));
        } else {
          result.unshift(...[map.get(base), map.get(base * 10)]);
        }
        base *= 10;
        num = (num - last) / 10;
      }
      return result.join("");
    }
    
    function integerToRomanOptimal(num) {
      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],
      ];
    
      let res = "";
    
      for (const [roman, val] of map) {
        while (num >= val) {
          res += roman;
          num -= val;
        }
      }
      return res;
    }
Dry answered 28/10, 2023 at 20:29 Comment(0)
F
-1

I wrote this from scratch for freecodecamp challenge. I hope this will help someone.

function convertToRoman(num) {

    var nums = [0, 0, 0, 0];

    var numsRom = ["", "", "", ""];

    var nRom = {
        I: "I",
        V: "V",
        X: "X",
        L: "L",
        C: "C",
        D: "D",
        M: "M"
    };
    /*
    1,
    5,
    10,
    50,
    100,
    500,
    1000
    */

    var i;

    nums[0] = Math.floor(num / 1000);
    nums[1] = Math.floor((num - nums[0] * 1000) / 100);
    nums[2] = Math.floor((num - nums[0] * 1000 - nums[1] * 100) / 10);
    nums[3] = num - nums[0] * 1000 - nums[1] * 100 - nums[2] * 10;

    //1000
    for (i = 0; i < nums[0]; i++) {
        numsRom[0] += nRom.M;
    }

    //100
    switch (nums[1]) {
        case 1:
        case 2:
        case 3:
            for (i = 0; i < nums[1]; i++) {
                numsRom[1] += nRom.C;
            }
            break;
        case 4:
            numsRom[1] += nRom.C + nRom.D;
            break;
        case 5:
            numsRom[1] += nRom.D;
            break;
        case 6:
        case 7:
        case 8:
            numsRom[1] += nRom.D;
            for (i = 0; i < nums[1] - 5; i++) {
                numsRom[1] += nRom.C;
            }
            break;
        case 9:
            numsRom[1] += nRom.C + nRom.M;
    }

    //10
    switch (nums[2]) {
        case 1:
        case 2:
        case 3:
            for (i = 0; i < nums[2]; i++) {
                numsRom[2] += nRom.X;
            }
            break;
        case 4:
            numsRom[2] += nRom.X + nRom.L;
            break;
        case 5:
            numsRom[2] += nRom.L;
            break;
        case 6:
        case 7:
        case 8:
            numsRom[2] += nRom.L;
            for (i = 0; i < nums[2] - 5; i++) {
                numsRom[2] += nRom.X;
            }
            break;
        case 9:
            numsRom[2] += nRom.X + nRom.C;
    }

    //1
    switch (nums[3]) {
        case 1:
        case 2:
        case 3:
            for (i = 0; i < nums[3]; i++) {
                numsRom[3] += nRom.I;
            }
            break;
        case 4:
            numsRom[3] += nRom.I + nRom.V;
            break;
        case 5:
            numsRom[3] += nRom.V;
            break;
        case 6:
        case 7:
        case 8:
            numsRom[3] += nRom.V;
            for (i = 0; i < nums[3] - 5; i++) {
                numsRom[3] += nRom.I;
            }
            break;
        case 9:
            numsRom[2] += nRom.I + nRom.X;
    }

    return numsRom.join("");
}

console.log("Number: " + 1234 + " is " + convertToRoman(1234));
Flycatcher answered 15/12, 2016 at 12:59 Comment(0)
R
-1

Probably the simplest solution:

rome = n => {
    b=0
    s=''
    for(a=5; n; b++,a^=7)
        for(o=n%a, n=n/a^0;o--;)
            s='IVXLCDM'[o>2?b+n-(n&=-2)+(o=1):b]+s
    return s
}

r = [rome(892),rome(3999)];

console.log(r);

I can't take credit though. This is vetalperko's solution on CodeSignal.

Retina answered 18/9, 2018 at 22:37 Comment(0)
B
-2

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;
}
Bawl answered 21/11, 2019 at 21:21 Comment(0)
P
-2

This solution can be used for small numbers (1-23). It can be used e.g. for city districts.

var rom = [[23,'XXIII'],[18,'XVIII'],[22,'XXII'],[17,'XVII'],[13,'XIII'],[ 8,'VIII'],[21,'XXI'],[19,'XIX'],[16,'XVI'],[ 3,'III'],[ 7,'VII'],[14,'XIV'],[12,'XII'],[ 2,'II'],[ 6,'VI'],[ 4,'IV'],[ 9,'IX'],[11,'XI'],[15,'XV'],[20,'XX'],[ 1,'I'],[ 5,'V'],[10,'X']];
var i2r = (x)=> rom.filter(y=>y[0]==x).pop()?.[1];
var r2i = (x)=> rom.map(y=>x.includes(y[1])?y[0]:0).filter(y=>y).shift();
Permian answered 3/3, 2022 at 14:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.