Say a Number
With the Corona-Lockdown in place “literally”, it was time to squeeze out some me-time to continue the quest for GO-Proficiency.
Sometimes you re-do optimization in your head so many times that it takes a whole day to see through the mistake you are making.
Trying to solve problem – Say.
input: 123,
expected: “one hundred twenty-three”,
For every such input number you need to translate and provide the English output.
The max limit goes till out a 100 billion.
I started it with a standard map definition which has few constants already in place.
var myMap = map[int]string{ 0: "zero", // 0 - Starts with zero. 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", 20: "twenty", 30: "thirty", 40: "fourty", 50: "fifty", 60: "sixty", 70: "seventy", 80: "eighty", 90: "ninety", 100: "hundred", 1000: "thousand", 1000000: "million", 1000000000: "billion", }
Step – 1
Addressing all numbers less than 100.
//tens It is a function that will convert < 100 func tens(i int) (string, bool) { // Valid for numbers less than hundred only. switch { case i > 13 && i < 20: return fmt.Sprintf("%s%s", myMap[i-10], "teen"), true case i > 20 && i < 29: return fmt.Sprintf("%s%s", "twenty-", myMap[i-20]), true case i > 30 && i < 40: return fmt.Sprintf("%s%s", "thirty-", myMap[i-30]), true case i > 40 && i < 50: return fmt.Sprintf("%s%s", "forty-", myMap[i-40]), true case i > 50 && i < 60: return fmt.Sprintf("%s%s", "fifty-", myMap[i-50]), true case i > 60 && i < 70: return fmt.Sprintf("%s%s", "sixty-", myMap[i-60]), true case i > 70 && i < 80: return fmt.Sprintf("%s%s", "seventy-", myMap[i-70]), true case i > 80 && i < 90: return fmt.Sprintf("%s%s", "eighty-", myMap[i-80]), true case i > 90 && i < 100: return fmt.Sprintf("%s%s", "ninety-", myMap[i-90]), true default: // If there is a numeric equivalent available in map. if val, ok := myMap[int(i)]; ok { return val, true } } //No match found in map or can be calculated return "", false }
Now time to build the logic upwards
//NumberConversion Converts the number func NumberConversion(i int64) (string, bool) { var s strings.Builder for i >= 0 { switch { case i == 0: if len(s.String()) == 0 { if val, ok := tens(int(i)); ok { fmt.Fprintf(&s, " %s", val) } } return strings.TrimSpace(s.String()), true case i < 100: if val, ok := tens(int(i)); ok { fmt.Fprintf(&s, " %s", val) } return strings.TrimSpace(s.String()), true } } return "", false }
This function allows all number conversion for elements less than 100 by calling the NumberConversion
function.
Step – 2 Number > 100 < 1000
Added a hundreds function
// hundreds Allows to compute the numeric equivalent of the 100-999 func hundreds(r int) (string, bool) { switch { case r == 0: return fmt.Sprintf("one %s", myMap[100]), true default: return fmt.Sprintf("%s %s", myMap[r], myMap[100]), true } }
and adding a new case to the function NumberConversion
case i >= 100 && i < 1000: r := int(i / 100) if val, ok := hundreds(r); ok { fmt.Fprintf(&s, " %s", val) } i %= 100
Similarly for elements greater than 1000
case i >= 1000 && i < 1000000: r := i / 1000 if val, ok := NumberConversion(r); ok { fmt.Fprintf(&s, " %s %s", val, myMap[1000]) } i %= 1000
For elements greater than million
case i >= 1000000 && i < 1000000000: r := i / 1000000 if val, ok := NumberConversion(r); ok { fmt.Fprintf(&s, " %s %s", val, myMap[1000000]) } i %= 1000000
And the last billion and less than 100 billion.
case i >= 1000000000 && i < 1000000000000: r := i / 1000000000 if val, ok := NumberConversion(r); ok { fmt.Fprintf(&s, "%s %s", val, myMap[1000000000]) } i %= 1000000000
Finally the function looks like below
//NumberConversion Converts the number func NumberConversion(i int64) (string, bool) { var s strings.Builder for i >= 0 { switch { case i == 0: if len(s.String()) == 0 { if val, ok := tens(int(i)); ok { fmt.Fprintf(&s, " %s", val) } } return strings.TrimSpace(s.String()), true case i < 100: if val, ok := tens(int(i)); ok { fmt.Fprintf(&s, " %s", val) } return strings.TrimSpace(s.String()), true case i >= 100 && i < 1000: r := int(i / 100) if val, ok := hundreds(r); ok { fmt.Fprintf(&s, " %s", val) } i %= 100 case i >= 1000 && i < 1000000: r := i / 1000 if val, ok := NumberConversion(r); ok { fmt.Fprintf(&s, " %s %s", val, myMap[1000]) } i %= 1000 case i >= 1000000 && i < 1000000000: r := i / 1000000 if val, ok := NumberConversion(r); ok { fmt.Fprintf(&s, " %s %s", val, myMap[1000000]) } i %= 1000000 case i >= 1000000000 && i < 1000000000000: r := i / 1000000000 if val, ok := NumberConversion(r); ok { fmt.Fprintf(&s, "%s %s", val, myMap[1000000000]) } i %= 1000000000 } } return "", false }
- All code available here