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!