Reputation: 4187
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
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
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