Roman Numeral Converter Challenge

Roman Numeral Converter Challenge
0.0 0

#91

I don’t know ES6, so here is my ES5 approach, that took a few attempts to get it working.

/*
** Function: Convert a number into a Roman Numeral.
** @function convertToRoman
** @summary  Convert a number into a Roman Numeral.
** @param 	 {number} 
** @see {@link https://jsperf.com/convertToRoman-eggs} 
** @returns  {string} Roman Numeral
*/
function convertToRoman(num) {
	'use strict';
  
  var base  = [1000,500,100,50,10,5,1];
  var roman = ['M','D','C','L','X','V','I'];
  var result = "";
  // 'I' = 1, 'V' = 5, 'X' = 10, 'L' = 50, 'C' = 100, 'D' = 500, 'M' = 1000
  
  base.forEach( function(value, i) {
    
    var ch = roman[i];
    if ( ch === 'V' || ch === 'L' || ch === 'D' ) {
      if ( num >= base[i+1]*9 ) {
        result += roman[i+1] + roman[i-1];
        num -= ( base[i-1] - base[i+1] );
      }
      else if ( num >= value - base[i+1] && num < value ) {
        result += roman[i+1] + roman[i];
        num -= ( base[i] - base[i+1] );
      }
    } 

    while ( num >= value ) {
      result += roman[i];
      num -= value;
    }
  });
  return result;
}

#92

I did something a bit similar.
I really like the .forEach() method.

function convertToRoman(num) {
var romanNum = [
[“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”]
] ;

var arr = num.toString().split("").reverse();
var rNums = [];
romanNum.forEach(function (a, i){
romanNum[i].forEach(function (b, j){
if((j + 1) == arr[i]){
rNums.unshift(b);
}
});

});
var result = rNums.join(’’);
return result;
}

convertToRoman(3643);


#93

I’ve been impressed by the clever use of Math.floor from other postings. I didn’t use it. I also like the string repeat method, which I wasn’t even aware of until looking through posts. My first attempt is below, which solved the problem but seems like a brute force attempt at solving the problem.


/*js hint esnext:true */

function wrapper(num){

const romNumerals = [["I","IV","V","IX"],["X","XL","L","XC"],["C","CD","D","CM"],"M"]; //array of arrays for Roman Numerals

const decimalNot = [[1,4,5,9],[10,40,50,90],[100,400,500,900],1000]; //corresponding array of arrays with decimal notation

function convertToString(num){
  
  const numSplitArray = num.toString().split("").reverse().map((currVal,index) => Number(currVal+"e"+index)); //convert to string and split number, adjust number based on ones,tens,hundreds,thousands
   
  return convert(numSplitArray);

}


 function convert(arr){
  
    
  let updateArray = [], //will  push all for loop results to this array
  
      i,
  
      joinedArray = [], //final array will be joined into this array
      
      arrLen = arr.length;
  
    
  for(i=0; i<3; i++){ //loop through the ones, tens, and hundreds 
    
    
  if(arr[i]===0 || !arr[i]) {
    
    continue; } //if the ones,tens, or hundreds place is zero, or undefined, skip current loop iteration
    
  else if(decimalNot[i].indexOf(arr[i]) === -1){ //if the corresponding roman numeral isn't present in the array, execute below
    
    
    let j=0, //define var for while loop
       
        inc = Math.pow(10,i); //increment based on the ones,tens,hundreds which is determined by the loop i value
    
    
    while(decimalNot[i].indexOf(arr[i]-j) === -1){ //while the number isn't present in the decimal notation array keep looping
      
      j += inc; //increment based on ones,tens,hundreds
      updateArray.push(romNumerals[i][0]); //push the corresponding roman numeral to the array (I, or X, or C)
    }
     
    updateArray.push(romNumerals[i][decimalNot[i].indexOf(arr[i]-j)]); //push the remainder (V, or L, or D)
    
    
  } else {  //if the number is directly available, go ahead and push it
    
    
    updateArray.push(romNumerals[i][decimalNot[i].indexOf(arr[i])]);
   
    
   }
    
  }
  
  if(arr[3]){ //if there is a thousands place, push an M for each thousand
    
  let thousandsValue = arr[3]/1000;
    
  for(let k=0; k<thousandsValue; k++){
    
    updateArray.push(romNumerals[3]);
    }
    
  } 
  
  joinedArray = updateArray.reverse().join(""); //reverse and join everything
  
  console.log(joinedArray);
  //return joinedArray;

}
  
  return convertToString(num);
  
}


wrapper(36);

I then started from scratch and was determined to use only a functional declarative approach. Less mutating arrays and looping, more .map and recursion. I think it’s easier to understand, but I’m not sure I decreased the amount of code by much. As I’ve read, clever and concise problem solving is what we’re really after.

/* jshint esnext: true */

//declarative version of the roman numeral problem, from scratch.  No mutating state (push, splice, etc.), no var or let, and a recursive function.



const romNumerals = [["I","IV","V","IX"],["X","XL","L","XC"],["C","CD","D","CM"],"M"]; //array of arrays for Roman Numerals

const decimalNot = [[1,4,5,9],[10,40,50,90],[100,400,500,900],1000]; //corresponding array of arrays with decimal notation


const convertToRoman = num => {
  
  const numSplitArray = num.toString()
                           .split("")
                           .reverse()
                           .map((currVal,index) => Number(currVal+"e"+index)); //convert to string and split number, adjust number based on ones,tens,hundreds,thousands
  
  return finalArray(numSplitArray);

}


 function reverseConvertNum (num,numIndex){
  
   const numIsZero = isZero(num, numIndex);
   
   if(numIsZero) return;
   
   const convNumber = convertNum(num, numIndex);
 
   if(!arrIncludesNum(num,numIndex)) return convNumber.split("").reverse().join("");
   
   return convNumber; 
}


const isZero = (num, numIndex) => num === 0;


function convertNum (num, numIndex){
  
     const adjustIndex = Number(1 + "e" + numIndex);
  
     if (arrIncludesNum(num, numIndex)) {
     
       return romNumerals[numIndex][decimalNot[numIndex].indexOf(num)]; }
 
    return romNumerals[numIndex][0] + convertNum(num-adjustIndex, numIndex);
  
  }


const arrIncludesNum = (num, numIndex) => decimalNot[numIndex].includes(num); //does the decimal array already contain the number
  

const hasThousands = array => array[3]; //does the number passed by the user have a thousands place


function writeThousands (array){
  
  if (hasThousands(array)) {
    
    let kArray = [];
    
    kArray.length = array[3]/1000;
    
   return kArray.fill(0).map(returnEms).join("");
    
  }
  
  return "";
    
}


const returnEms = num => "M";


function finalArray (array){
  
  const newArray = array.slice(0,3).map(reverseConvertNum).reverse().join(""),
      
           
        thousandsPlace = writeThousands(array);  
  
    
  return thousandsPlace + newArray;
} 
 


console.log(convertToRoman(700));


Cheers!


#94

This is a really cool thread. I’ve seen some other examples that are a lot like mine, but there were some cool ideas that I would never have thought of, (and some that were over my head, too)

This is what I did:

function convertToRoman(num) {
  function roman(n){
    switch(n){
      case 0:
        return ['I','II','III','IV','V','VI','VII','VIII','IX'];
        break;
      case 1:
        return ['X','XX','XXX','XL','L','LX','LXX','LXXX','XC'];
        break;
      case 2:
        return ['C','CC','CCC','CD','D','DC','DCC','DCCC','CM'];
        break;
      case 3:
        return ['M','MM','MMM','MMMM'];
        break;
    }
  }

 let arr = num.toString().split('');
 // console.log(arr);
 let newArr = [];
  for ( let i=0; arr.length>0; i++ ) {
    let n = arr.pop();
    let place = roman(i);
    //console.log(parseInt(n));
    if ( parseInt(n) > 0 ) {
      newArr.push(place[parseInt(n)-1]);
    }
  }
  let str = '';
  while ( newArr.length>0 ){
    str += newArr.pop();
  }
  return str;
}

convertToRoman(36);