Skip to content

Instantly share code, notes, and snippets.

@kurtbartholomew
Last active April 28, 2017 18:57
Show Gist options
  • Save kurtbartholomew/02d6821b4dc9e9e1baef7a4b928157da to your computer and use it in GitHub Desktop.
Save kurtbartholomew/02d6821b4dc9e9e1baef7a4b928157da to your computer and use it in GitHub Desktop.
numberToEnglish
/*
Instructions:
This solution requires Node to be installed on the target system.
No version requirement exists, but it is suggested that you use
6.0 or higher.
Your node version may be checked by typing `node -v` into your terminal.
To run the solution, simply type `node numberToEnglish.js`.
If all tests pass, you should see the `All tests passed!` message in your terminal.
Comments:
- I decided on an iterative solution to prevent discussion about stack overflow.
- It could be argued to use a string / char array instead of string concatenation but I find that perf for those are somewhat similar with how the v8 engine optimizes string concatenation.
- For simplicity’s sake, I’ve used node’s assert module for unit tests as opposed to something like mocha or jasmine
- I’ve left TODO’s in the code for the enhancements I would make
*/
// Solution Time Complexity: O(n * k) where n is # of digits and k is the size of the largest string
// Solution Space Complexity: O(n * k) " "
(function(){
'use strict';
const assert = require('assert');
const largeCountLookup = {1:"thousand", 2:"million", 3:"billion", 4:"trillion", 5:"quadrillion"};
const tensLookup = {2:"twenty", 3:"thirty", 4:"forty", 5:"fifty", 6:"sixty", 7:"seventy", 8:"eighty", 9:"ninety"};
const teensLookup = {10:"ten", 11:"eleven", 12:"twelve", 13:"thirteen", 14:"fourteen",
15:"fifteen", 16:"sixteen", 17:"seventeen", 18:"eighteen", 19:"nineteen"};
const singleDigitLookup = {1:"one", 2:"two", 3:"three", 4:"four", 5:"five", 6:"six", 7:"seven",
8:"eight", 9:"nine"};
function numberToEnglish(intNumber) {
if(intNumber === undefined) { throw Error("The input to numberToEnglish cannot be undefined"); }
if(typeof intNumber !== 'number') { throw Error("The input must be a number"); }
if(Math.abs(intNumber) % 1 !== 0) { throw Error("The input must be an integer"); }
if(Math.abs(intNumber) === 0) { return "zero"; }
const isNegative = (intNumber < 0);
if(isNegative) { intNumber *= -1; }
const numberSectionStack = [];
let largeCountCounter = 0;
while(intNumber !== 0) {
numberSectionStack.push(intNumber % 1000);
++largeCountCounter;
intNumber = Math.floor(intNumber / 1000);
}
let resultString = "";
while(numberSectionStack.length) {
resultString += assembleStringForSection(numberSectionStack.pop(), --largeCountCounter);
}
return isNegative ? "negative " + resultString : resultString;
}
function assembleStringForSection(sectionInt, largeCountCounter) {
let result = "";
if(sectionInt === 0) { return result; }
if(sectionInt >= 100) {
result += singleDigitLookup[Math.floor(sectionInt / 100)] + " hundred ";
sectionInt = sectionInt % 100;
}
if(sectionInt >= 10) {
if(sectionInt < 20) {
result += teensLookup[sectionInt] + " ";
sectionInt = 0;
} else {
result += tensLookup[Math.floor(sectionInt / 10)] + " ";
sectionInt = sectionInt % 10;
}
}
if(sectionInt > 0) {
result += singleDigitLookup[sectionInt];
}
// TODO: Clean up logic around spacing (change to just placing spaces before words)
// TODO: Add commas after each large number place that isn't all 0's
let largeNumberPlace = largeCountLookup[largeCountCounter] === undefined ? "" : largeCountLookup[largeCountCounter];
if(largeCountCounter > 0) { largeNumberPlace = " " + largeNumberPlace + " "; }
return result + largeNumberPlace;
}
assert.throws(numberToEnglish, /cannot be undefined/, "Should throw an error if input is undefined");
assert.throws(() => numberToEnglish("wrong"), /must be a number/, "Should throw an error if input is not a number");
assert.throws(() => numberToEnglish(4.5), /must be an integer/, "Should throw an error if input is not an integer");
assert.equal(numberToEnglish(0),"zero", "Should return zero correctly");
assert.equal(numberToEnglish(5),"five", "Should return a single digit correctly");
assert.equal(numberToEnglish(55),"fifty five", "Should return a two digit number correctly");
assert.equal(numberToEnglish(555),"five hundred fifty five", "Should return a three digit number correctly");
assert.equal(numberToEnglish(5555),"five thousand five hundred fifty five", "Should return a four digit number correctly");
assert.equal(numberToEnglish(1000000001),"one billion one", "Should not output any text for all zero intermediate sections");
assert.equal(numberToEnglish(-1000000001),"negative one billion one", "Should return negative numbers correctly");
console.log("All tests passed!");
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment