devdropper87
devdropper87

Reputation: 4187

Roman Numeral Translator Using JavaScript

I got this to work without using underscore, but as an extra challenge I'm trying to convert Roman Numerals to Arabic numbers using underscore. Below is my attempt. It works, except for in the case of the "next" number being greater than the "current" one. I'm really not sure why, but when I check for if(next>= num), that if block is not even being executed?

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

var translateRomanNumeral = function(roman) {
  // if it's not in the digit values object, return null
  for (var i = 0; i < roman.length; i++) {

    if (!(roman[i] in DIGIT_VALUES)) {
      return null;
    }

  }
  //with underscore:
 var romanTranslated =  reduce(roman, function(memo, letter, i) {
    var prev = DIGIT_VALUES[roman[i - 1]];
    var num = DIGIT_VALUES[letter];
    var next = DIGIT_VALUES[roman[i + 1]];
    if (next === undefined || next <= num) {
      return memo + num;
    }

This is not being executed for some reason:

    if (next >= num) {
      var diff = num - prev;
      console.log(diff);
      return memo + (diff - prev);
    }
  }, 0);
  // grab the first one

  //1
  // console.log(num);
return romanTranslated;


};

console.log(translateRomanNumeral("LXIV")); //returns 66 ---> should return 64
console.log(translateRomanNumeral("CI")); //working --> returns 101
console.log(translateRomanNumeral("MMMMCCL")); // working ---> returns 4250.
//works!

Upvotes: 0

Views: 598

Answers (2)

Nina Scholz
Nina Scholz

Reputation: 386654

You could use a concise version with Array#reduce and a look at the actual value and the next value.

function parseRoman(s) {
    var val = { M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 };
    return s.toUpperCase().split('').reduce(function (r, a, i, aa) {
        return r + (val[a] < val[aa[i + 1]] ? -val[a] : val[a]);
    }, 0);
}

console.log(parseRoman("LXIV"));    //   64
console.log(parseRoman("IX"))       //    9
console.log(parseRoman("IV"))       //    4
console.log(parseRoman("CI"));      //  101
console.log(parseRoman("MMMMCCL")); // 4250

Upvotes: 2

devdropper87
devdropper87

Reputation: 4187

The main source of my error was that the way I had defined reduce did not allow me access to the index while iterating. I updated my reduce function, then it worked after a little debugging:

var DIGIT_VALUES = {
  I: 1,
  V: 5,
  X: 10,
  L: 50,
  C: 100,
  D: 500,
  M: 1000
};
var each = function(collection, iterator) {
  if (Array.isArray(collection)) {
    for (var i = 0; i < collection.length; i++) {
      iterator(collection[i], i, collection);
    }

  } else {
    for (var key in collection) {
      iterator(collection[key], key, collection);
    }
  }

};

var reduce = function(collection, iterator, total) {
  if (total == undefined) {
    total = collection.shift();
  }


  each(collection, function(val, i) {
    total = iterator(total, val, i);
  })
  return total;
};

var translateRomanNumeral = function(roman) {
  if (typeof(roman) !== 'string') {
    return null;
  }
  if (!roman) {
    return 0;
  }
  // if it's not in the digit values object, return null
  for (var i = 0; i < roman.length; i++) {

    if (!(roman[i] in DIGIT_VALUES)) {
      return null;
    }

  }
  //with underscore:

  return reduce(roman, function(memo, letter, i) {
    var num = DIGIT_VALUES[letter];
     //console.log(i);
    //how do you acess the next item in a collection in reduce?
    var next = DIGIT_VALUES[roman[Number(i) + 1]];
    // console.log(Number(i) + 1);
    // console.log(next);

      if ( next === undefined || next <= num) {
        return memo + num;
        //console.log(memo);
      }

      else {
        // var diff = num - prev;
        // console.log(diff);
        return memo - num;
        // memo = memo + (next - num);
      }


    // return memo;
  }, 0);

};

console.log(translateRomanNumeral("LXIV")); //returns 66 ---> should return 64
console.log(translateRomanNumeral("IX")) // should return 9
console.log(translateRomanNumeral("IV")) /// should return 4

console.log(translateRomanNumeral("CI")); 
//working --> returns 101
console.log(translateRomanNumeral("MMMMCCL")); 
// working ---> returns 4250.
//works!

Upvotes: 0

Related Questions