Here’s my solution. I can now see that many of the other, more efficient solutions are essentially doing the same thing as I’m doing, except instead of the copy-paste of each block in the if-else, the equivalent to the concatenation is implemented once, and objects are created to map the Roman numerals onto their specific values.
In that case, my question is: how does one gain the intuition to simplify the process in these ways? Is it just a matter of time/doing exercises/reading other people’s solutions and learning from them?
All the things you mentioned are important. If you only do exercises but don’t look at other people’s solutions, you get better with the tools you already know. But you won’t know the limits of your knowledge.
When you finished an exercise, go and look at other peoples solutions - try to understand what they did and then try to use that way on a similar problem yourself.
Trust me, if you constantly see people using some way you don’t know, you really want to figure out how to do it that way yourself
I was trying to come with a different solution but… Too late.
I have sent this solution (similar to others I have saw here I am afraid, nothing new under the stars ):
function convertToRoman(num) {
const romansArabics = {
"M": 1000,
"CM": 900,
"D": 500,
"CD": 400,
"C": 100,
"XC": 90,
"L": 50,
"XL": 40,
"X": 10,
"IX": 9,
"V": 5,
"IV": 4,
"I": 1
};
let romans = "";
let arabic = 0;
// console.log({num, romans, arabic});
// Loop throw all romans (properties) in romansArabics object
for (const roman in romansArabics) {
// Assign the value of the property (roman) to the arabic variable
arabic = romansArabics[roman];
// console.log(`Arabic: ${romansArabics[roman]} | Roman ${roman}`);
// Loops while number minus arabic value is bigger or equal to 0
while (num - arabic >= 0) {
// Concat the roman property to romans variable
romans += roman;
// Subtract the arabic value to the number, before the new iteration
num -= arabic;
// console.log({num, romans, arabic, roman});
}
}
return romans;
}
console.log(convertToRoman(2022));
Just revisiting some solutions and I do not see anyone mentioning the little optimization you applied by removing the ‘processed’ inner array once handled. Nice! I do like this solution.
This is a very nice approach to solving this solution. I like how you applied recursion and presented the code so compact that it remains easily readable. Nice!
My belated solution - I would not have known to use “while” without doing the course or reviewing other people’s answers. I’m not sure of the thought processes people use to decide whether to use switch case, for loops or while - is this something that will just come naturally to me, the more I practice?
Also, when I started doing this solution, I was doing it back to front and wondering why, e.g. (24) would always return “IV”. I also initially missed out many of the + signs before the = in the second lines of the while statements, which gave some interesting results.
function convertToRoman(num) {
let newStr = "";
while (num >= 1000) {
newStr += "M";
num -= 1000;
}
while (num >= 900) {
newStr += "C" + "M";
num -= 900;
}
while (num >= 600) {
newStr += "D" + "C";
num -= 600;
}
while (num >= 500) {
newStr += "D";
num -= 500;
}
while (num >= 400) {
newStr += "C" + "D";
num -= 400;
}
while (num >= 100) {
newStr += "C";
num -= 100;
}
while (num >= 90) {
newStr += "X" + "C";
num -= 90;
}
while (num >= 50) {
newStr += "L";
num -= 50;
}
while (num >= 40) {
newStr += "X" + "L";
num -= 40;
}
while (num >= 39) {
newStr += "I" + "X" + "L";
num -= 39;
}
while (num >= 10) {
newStr += "X";
num -= 10;
}
while (num >= 9) {
newStr += "I" + "X";
num -= 9
}
while (num >= 5) {
newStr += "V";
num -= 5;
}
while (num >= 4) {
newStr += "I" + "V";
num -= 4;
}
while (num >= 1) {
newStr += "I";
num -= 1;
}
return newStr;
}
console.log(convertToRoman(999));
No worries, try to solve the problems with your actual knowledge you could back later on and try to solve again.
The most important it is make your code and after you can try to make it more readable, prettier or more efficient. It is normal.
Jane don’t be hard on yourself. Congratulate yourself often after you try or if you succeed, it doesn’t matter. When I’m stuck, after I try I play a song that makes me dance and I start dancing.
You could use Pomodore Technique and play a song after those 25 min of focusing, for example. It is a good technique for learning and working.
Happy coding!! Repeat after me: You rock Jane!!
P.S. Speaking about rocks… One of my favourites moments… I hope it makes you laugh.
In my revised solution here, I created an array for the Roman numerals and their Arabic counterparts. This way, when I iterated through, I was sure that it would start with the biggest number, and then work its way down to the smallest one, since the array is an ordered structure.
I noticed that some other student solutions used objects instead but iterated through in the same way, such as this one.
I used an array because I thought that the keys would not maintain a strict order in an object, meaning that I couldn’t be sure that it would be testing from largest to smallest value, and that seems to be confirmed in this lesson, which notes: “Objects do not maintain an ordering to stored keys like arrays do; thus a key’s position on an object, or the relative order in which it appears, is irrelevant when referencing or accessing that key.”
So I guess my question is: why is this algorithm working predictably when using objects instead of arrays?
When iterating an object, the system looks first for Strings that look like integer keys, and iterates those in numeric order, then iterates the remaining String keys, in insertion order, then iterates the Symbols, again in insertion order.
So it works here because all the keys are letters and are inserted in the right order from the biggest to the lowest.
That’s obviously not something you want to rely on if you use the object for more than for storing these numerals
edit:
Beware of trying to have the same key in your object as a number and as a string:
the key is always stored as a string and that results in having the key only one time with the value of the last insertion.
prints first
prints second
prints third
prints fourth
prints fifth
It seems to me that, all things being equal, it’s probably good practice to use an array when one wants to preserve order, rather than use an object and then remember and count on this specific functionality.