I have a challenge, which is to create a JavaScript function that turns a given number into the string representation. For example:
console.log(inToEnglish(15))
should print fifteen
console.log(inToEnglish(101))
should print one hundred one
and so on...
This challenge covers Non-Negative, greater than zero Integer numbers.
I have accomplished this objective with the following code:
var b4Twenty = ["one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
"seventeen", "eighteen", "nineteen"
];
var b4Hundred = ["twenty", "thirty", "forty", "fifty", "sixty", "seventy",
"eighty", "ninety"
];
function intToEnglish(n) {
return translator(n).trim();
}
function translator(n) {
if( n == 0)
return "";
else if (n <= 19)
return b4Twenty[n - 1] + " ";
else if (n <= 99)
return b4Hundred[Math.floor(n / 10 - 2)] + " " + translator(n % 10);
else if (n <= 199)
return "one hundred " + translator(n % 100);
else if (n <= 999)
return translator(Math.floor(n / 100)) + "hundred " + translator(n % 100);
else if (n <= 1999)
return "one thousand " + translator(n % 1000);
else if (n <= 999999)
return translator(Math.floor(n / 1000)) + "thousand " + translator(n % 1000);
else if (n <= 1999999)
return "one million " + translator(n % 1000000);
else if (n <= 999999999)
return translator(Math.floor(n / 1000000)) + "million " + translator(n % 1000000);
else if (n <= 1999999999)
return "one billion " + translator(n % 1000000000);
else if (n <= 999999999999)
return translator(Math.floor(n / 1000000000)) + "billion " + translator(n % 1000000000);
else if (n <= 1999999999999)
return "one trillion " + translator(n % 1000000000000);
else if(n <= 999999999999999)
return translator(Math.floor(n / 1000000000000)) + "trillion " + translator(n % 1000000000000);
else if (n <= 1999999999999999)
return "one quadrillion " + translator(n % 1000000000);
else
return translator(Math.floor(n / 1000000000000000)) + "quadrillion " + translator(n % 1000000000000000);
}
This is my recursive function to achieve the given goal. It works, and it takes 65ms to complete the battery of 50 tests.
However, I have some concerns regarding its performance:
- Given that recursive functions are usually slower than iterative ones, is there a way to make this iterative?
- Should I use a
switch
case, or is myif
statement OK? - I keep using
Math.floor
to round the numbers and find the indexes. Perhaps there is a better solution out there without using this technique? - I have to wrap the translator function (who does all the work) into another function because I need to
trim
the final result of extra spaces. Is there a way I can avoid this?
I am open to suggestions on how to improve this. Thanks!
2 Answers 2
Interesting question! I came up with a premature function in my spare time. There are many TODOs should be done, but I think that its a good start.
First, instead of splitting logic into array, I would rather use an mapping object (dictionary).
const mapNumberToString = {
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
6: "six",
7: "seven",
8: "eight",
9: "nine",
10: "ten",
11: "eleven",
12: "twelve",
13: "thirteen",
14: "fourteen",
15: "fifteen",
16: "sixteen",
17: "seventeen",
18: "eighteen",
19: "nineteen",
20: "twenty",
30: "thirty",
40: "forty",
50: "fifty",
60: "sixty",
70: "seventy",
80: "eighty",
90: "ninety",
100: "hundred",
1000: "thousand",
1000000: "million",
1000000000: "billion",
1000000000000: "trillion",
1000000000000000: "quadrillion"
};
Then, my function goes like this...
const intToEnglish = (n) => {
const arr = n.toString().split('').map(s => +s);
let eng = "0";
// under 20
if (n <= 20 && n > 0) {
eng = mapNumberToString[n];
}
// 21 ~ 99
else if (arr.length < 3) {
eng = [
mapNumberToString[arr[0]*10],
mapNumberToString[arr[1]]
].join(' ');
}
// 100 ~ 999
else if (arr.length < 4) {
eng = [
mapNumberToString[arr[0]],
mapNumberToString[100],
intToEnglish(n % 100)
].join(' ');
}
// above 1000
else {
const exp = Math.pow(1000, Math.floor( (arr.length - 1) / 3));
eng = [
intToEnglish(Math.floor(n / exp)),
mapNumberToString[exp],
intToEnglish(n % exp)
].join(' ');
}
return eng.trim();
};
Taking advantages of array
and recursive function, and also javascript weird undefined
to make this magic happen.
1: one
5: five
10: ten
15: fifteen
20: twenty
25: twenty five
100: one hundred
105: one hundred five
115: one hundred fifteen
120: one hundred twenty
212: two hundred twelve
232: two hundred thirty two
999: nine hundred ninety nine
1000: one thousand
1234: one thousand two hundred thirty four
12345: twelve thousand three hundred forty five
123456: one hundred twenty three thousand four hundred fifty six
234100: two hundred thirty four thousand one hundred
1032001: one million thirty two thousand one
5000021: five million twenty one
810238903242: eight hundred ten billion two hundred thirty eight million nine hundred three thousand two hundred forty two
In this way, you can easily add up your mapping object without changing your code (quintillion, sextillion...). Plus, there are less if statement, which I think is easier to read, in my own opinion of course lol.
Again, there is so much to improve, and I currently don't have that much time :(.
intToEnglish(-1)
returns "undefined", which might not be what you want. Same goes for fractional values, although I guess that case could be waved... if you only support integers. Even so, you might want to add a check. At the very least, add a comment - problem descriptions are kept separate from your code right now, and that makes it non-obvious that it doesn't support such things!
Negative numbers could be supported via prepending "minus", then translator(Math.abs(n))
.
-
\$\begingroup\$ Apologies, it was a typo in my post ! The code is for integers (as the title indicates), but I will add the other parts of the information missing. The code is correct, thank you for noticing ! rep++ \$\endgroup\$Flame_Phoenix– Flame_Phoenix2016年04月05日 13:27:13 +00:00Commented Apr 5, 2016 at 13:27
Explore related questions
See similar questions with these tags.
before
and notb4
. Also I think that before isn't the best choice for what you want to express. Below is a better fit. \$\endgroup\$