Roman Numerals - is this a basic solution? [SPOILER]

Hi, just a wonderin’ because I have a smug warm feeling at not using alot of reference to accomplish this challenge and I feel that that feeling may be misplaced as I have a habbit of producing very noob javascript!

So, is there a more concise way or a js.method() that a more experience developer would approach this challenge with? Does my logic take me round the houses or on this occasion is it straight to the point?

nb. The .map(Number) is the bit I referenced and in all honestly I don’t really understand what its doing there, just that it doesnt work without it. I know what .map is doing and I have seen Number() on mdn but it doesn’t really corelate to me yet, being inside the .map. If someone could explain what its doing, that’d be great.

Cheers

Mark

EDIT: I’ve worked out waht my (Number) is doing, or rather remembered… its to make the number that i’ve converted to a string and then split, back into number within the .map array.

numerals = {
	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',
	4000: 'MMMM',
	5000: 'MMMMM'
};
function convertToRoman(num) {
  var array = [];
  num = num.toString().split("").map(Number);  
  num.reverse(); 
  for (var i = 0; i < num.length; i++){
  	var multiplyer = Math.pow(10, [i]);
    numeral = numerals[num[i]*multiplyer];
    array.push(numeral);
  }
  converted = array.reverse().join('');
  return converted;
} 
convertToRoman(649);

Here’s mine to compare, I’d say yours was a lot neater and concise.


function convertToRoman(num) {
  var units = num % 10;
  var tens = Math.floor((num % 100) / 10 );
  var hundreds = Math.floor((num % 1000) / 100 );
  var thousands = Math.floor((num % 10000) / 1000 );
  var romanArr = [];
  
  switch (thousands){
    case 1: 
      romanArr.push('M');
      break;
    case 2: 
      romanArr.push('MM');
      break;
    case 3: 
      romanArr.push('MMM');
      break;
    case 4: 
      romanArr.push('MMMM');
      break;
  }
  
  switch (hundreds){
    case 1: 
      romanArr.push('C');
      break;
    case 2: 
      romanArr.push('CC');
      break;
    case 3: 
      romanArr.push('CCC');
      break;
    case 4: 
      romanArr.push('CD');
      break;
    case 5: 
      romanArr.push('D');
      break;
    case 6: 
      romanArr.push('DC');
      break;
    case 7: 
      romanArr.push('DCC');
      break;
    case 8: 
      romanArr.push('DCCC');
      break;
    case 9: 
      romanArr.push('CM');
      break;
  }
  
  switch (tens){
    case 1: 
      romanArr.push('X');
      break;
    case 2: 
      romanArr.push('XX');
      break;
    case 3: 
      romanArr.push('XXX');
      break;
    case 4: 
      romanArr.push('XL');
      break;
    case 5: 
      romanArr.push('L');
      break;
    case 6: 
      romanArr.push('LX');
      break;
    case 7: 
      romanArr.push('LXX');
      break;
    case 8: 
      romanArr.push('LXXX');
      break;
    case 9: 
      romanArr.push('XC');
      break;
  }
  
  switch (units){
    case 1: 
      romanArr.push('I');
      break;
    case 2: 
      romanArr.push('II');
      break;
    case 3: 
      romanArr.push('III');
      break;
    case 4: 
      romanArr.push('IV');
      break;
    case 5: 
      romanArr.push('V');
      break;
    case 6: 
      romanArr.push('VI');
      break;
    case 7: 
      romanArr.push('VII');
      break;
    case 8: 
      romanArr.push('VIII');
      break;
    case 9: 
      romanArr.push('IX');
      break;
  }
  
  return romanArr.join('');
}

oh, i don’t know about that @joelpeyton .

Take the switch out of yours and the object out of mine and you have a much simpler way of getting the right abacuss column (whats the correct term for that anyway?)

I did think of a switch at first, but I never even thought of getting the digits that way.

OUCH!!! That kind of makes me feel sick. Joking apart, it’s great to see these concise solutions, hopefully I can emulate them as I progress.

1 Like

Hi,

Thanks for that, I think the object idea came because i’ve just completed the intermediate front end challenges and they were all about objects really.

I’ve been staring at your code for 15 minutes and still it looks like magic! I think, your for loop is itterating the length of numeric (being the same length as roman) and matching the indexes, and then you are appending roman[i] acordingly, but beyond that its like advanced technology to me :slight_smile: like i have no idea what thei in var output is doing there!

I know i’ve touched on the while loops, but I think I should revisit as i never used one so far.

How wrong was I??

I really like the whole approach there, "for this particular number, while it's still bigger, just add another M to output and chop off 1000 from num"

Stroke of genius that looks so obvious in hindsight.

Another helpful post - I properly ‘get’ what the while loop is doing inside that iteration now.

Thanks alot.

Mark

1 Like

I feel a bit silly looking at both of your solutions, guys. It honestly never crossed my mind to just hard-code the weird numbers (like IX, CD, XC, XL, etc.) into it. Boy does that make things simpler… I think I had some kind of an idea that I wanted mine to be able to handle more hypothetical roman numerals than actually exist…

function convertToRoman(num) {
  var roman = "";
  var chars = [
    ["M", 1000],
    ["D", 500],
    ["C", 100],
    ["L", 50],
    ["X", 10],
    ["V", 5],
    ["I", 1]
  ];
  
  var i = 0;
  function romanifyChar(num, charIndex) {
    var str = "";
    var c = chars[charIndex];
    var q = (num - (num % c[1])) / c[1];
    
    if (num.toString().charAt() == 9 && num / c[1] >= 1) {
      str += chars[charIndex + 1][0] + chars[charIndex - 1][0];
      num -= c[1] + (4 * chars[charIndex + 1][1]);
    } else if (q === 4) {
      str = c[0] + chars[charIndex - 1][0];
      num = num % c[1];
    } else {
      while (q > 0) {
        str += c[0];
        q--;
      }
      num = num % c[1];
    }
    i++;
    roman += str;
    return num;
  }
  
  while (num > 0) {
    num = romanifyChar(num, i);
  }
  return roman;
}

…if this mess^ doesn’t make your code look great for a beginner attempt @MARKJ78, I don’t know what will :wink: …a week after writing it, I’m having trouble understanding what it even does :stuck_out_tongue:

1 Like

@gracenut , I usually go back and comment almost every line of challenges for that very reason… i’d show you the rediculous level of commenting I can do but all my solutions from the basic algo’s have disapeared :rage:

so anyway I usually do something like this…

function convertToRoman(num) {

//empty array to dump iterations into
  var array = [];

//convert number to array of digits - can only split a string so (number) in map makes it a number again
  num = num.toString().split("").map(Number);  

// turn the array around so I can use it like an abacuss
  num.reverse(); 

//itterate the array
  for (var i = 0; i < num.length; i++){

        //Apply a power of 10 to array index numbers to make my abacuss work
  	var multiplyer = Math.pow(10, [i]);

     //make a new variable that takes current digit, applies the correct multiplyer and uses as an object key (oops forgot     the var here to keep scope local)
    numeral = numerals[num[i]*multiplyer];

//send to array
    array.push(numeral);
  }

  //process array - turn back around and return a string, then return the string for use
  converted = array.reverse().join('');
  return converted;

} 

convertToRoman(649);
1 Like

And also @gracenut ,

I don’t think that’s silly at all, I think that’s what I first thought, and then second and third thought until I realised/thought I was going to have to actually write them all out!

I am aware of the limitations of this challenge, in terms of hypothetical or really really big numbers - for instance according to the link given for numerals, 5k and upwards have their own letter, an overscored uppercase, which I don’t think we can have in JavaScript - which leaves us with loads of MMMMMMMMMMM’s.

Pixt solution and yours will work for that (although with MMMMMM’s), mine, however, will only work up to the number I would have hard coded in so its inherently flawed… therefore, yours is better because it actually works :slight_smile:

1 Like

Nothing wrong with all that commenting @MARKJ78 , good practise I’d say.
As for your solutions they should all be viewable if you click your profile picture or follow this link:

Don’t go hiding my solutions

1 Like

Thankyou… they do appear to be there when accessed that way :thumbsup:

I think commenting like that also drives it into your memory what you’ve done.

@P1xt I’m assuming you have created three new variables in the above line of code?


var output = ‘’;
var i;
var len = numeric.length;

I’ve never seen assignment done that way before, confused me initially, I was trying to work out what data type it would be.

OK great but why not code:

var output = ‘’;

for (var i = 0; i < numeric.length; i++) {

}

Thank you, I am a little wiser for knowing.

Thank you so much for the colsole.log explanations in your code, finally this challenge made sense to me. I couldn’t put my head around “output += roman[i]; and num -= numeric[i];” part and after I went through your explanations it all made a perfect sence to me, well almost…

Hense a question - how roman[i] knows that ‘M’ is equivalent to ‘1000’ in numeric array? You are iterating over numeric with numeric.length, but I can’t see where do you iterate over roman array? Is it because you declared ‘i’ outside of for loop, so it is available to roman without puting it through a for loop?

Whats num -= numeric[i]; mean? This is how I feel right now looking at your code:

Feel free to checkout my solution and give me feedback. I have no idea how you to where you did. I understand after reading your code but I’m kind of but hurt right now. lol

This is amazing, I had no idea it works like that, thank you so much for offering such a detailed explanation to me :blush: I’m very grateful! Now it all became clear and understandable how loops work with arrays.

1 Like

@P1xt What a great solution. Not to be vain but I ended up really liking mine. I got some inspiration from from a key/value pair solution and went from there.

function convertToRoman(num) {
     
      var number = num.toString();
      
      //get the number of zeros needed to make the string's length be 4
      var len = 4 - number.length;

      //get those zeros from a string and append them to the front
      number = "000".substr(0, len) + number;
        
      var ones = ["","I","II","III","IV","V","VI","VII","VIII","IX"];
      var tens = ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"];
      var hundreds = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"];
      var thousands = ["", "M", "MM", "MMM"];
     
      var values = [thousands, hundreds, tens, ones];
     
      var numeral = "";
      for (var i = 0; i < number.length; i++) {
          
          var numeralIndex = parseInt(number[i]);
          
          numeral += values[i][numeralIndex];
      }
        
      return numeral;
    }

I just ended hardcoding all values into some kind of “dictionary” and taking them from it. Not an elegant solution, but was easiest for me.

function convertToRoman(num) {
  var arr = (num+"").split("");
  
  var multi = 1;
  
  for(var i=arr.length-1; i>=0; i--){
    arr[i] = arr[i] * multi;
    multi *= 10;
  }
  
  var dict = { 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", 4000:"MMMM" };
  
  
  for (var j=0; j<arr.length;j++){
    arr.splice(j, 1, dict[arr[j]]);
  }  
  num = arr.join("");
    
  return num;
}