3

This is a probable answer of my question in stack overflow.Integer to word conversion

At first I have started with dictionary. Then I came to know it is obsolete. So now I use Map instead of dictionary. My code is work well for number till Millions. But the approach I take here is a naive approach. The main problem of this code is

First: Huge numbers of variable use

2nd: Redundant code block as per program requirement

3rd: Multiple if else statement

I am thinking about this problems

Solution for 2nd problem: using user define function or macros to eliminate redundant code block

Solution for 3rd problem: Using switch case

My code:

public class IntegerEnglish {
public static void main(String args[]){
    Scanner in=new Scanner(System.in);
    System.out.println("Enter the integer");
    int input_number=in.nextInt();
    Map<Integer,String> numbers_converter = new HashMap<Integer,String>();
    Map<Integer,String> number_place = new HashMap<Integer,String>();
    Map<Integer,String> number_2nd = new HashMap<Integer,String>();
    numbers_converter.put(0,"Zero");
    numbers_converter.put(1,"One");
    numbers_converter.put(2,"Two");
    numbers_converter.put(3,"Three");
    numbers_converter.put(4,"Four");
    numbers_converter.put(5,"Five");
    numbers_converter.put(6,"Six");
    numbers_converter.put(7,"Seven");
    numbers_converter.put(8,"Eight");
    numbers_converter.put(9,"Nine");
    numbers_converter.put(10,"Ten");
    numbers_converter.put(11,"Eleven");
    numbers_converter.put(12,"Twelve");
    numbers_converter.put(13,"Thirteen");
    numbers_converter.put(14,"Fourteen ");
    numbers_converter.put(15,"Fifteen");
    numbers_converter.put(16,"Sixteen");
    numbers_converter.put(17,"Seventeen");
    numbers_converter.put(18,"Eighteen");
    numbers_converter.put(19,"Nineteen");
    number_place.put(3,"Hundred");
    number_place.put(4,"Thousand");
    number_place.put(7,"Million");
    number_place.put(11,"Billion");
    number_2nd.put(2,"Twenty");
    number_2nd.put(3,"Thirty");
    number_2nd.put(4,"Forty");
    number_2nd.put(5,"Fifty");
    number_2nd.put(6,"Sixty");
    number_2nd.put(7,"Seventy");
    number_2nd.put(8,"Eighty");
    number_2nd.put(9,"Ninty");

   if(input_number== 0){
       System.out.println("zero");
   }
   else if(input_number>0 && input_number<19){
       System.out.println(numbers_converter.get(input_number));
   }
   else if(input_number>19 && input_number<100){
       int rem=input_number%10;
       input_number=input_number/10;
       System.out.print(number_2nd.get(input_number));
       System.out.print(numbers_converter.get(rem));
   }
   else if(input_number==100){
       System.out.println(number_place.get(3));
   }
   else if(input_number>100 && input_number<1000){
       int reminder=input_number%100;
       int r1=reminder%10;
       int q1=reminder/10;
       int quot=input_number/100;
       System.out.print(numbers_converter.get(quot) + "hundred");
       if(reminder>0 && reminder<20){
           System.out.print(numbers_converter.get(reminder));
       }
       else{
           System.out.println(number_2nd.get(q1) + numbers_converter.get(r1));
       }
   }
   else if(input_number==1000){
       System.out.println(number_place.get(4));
   }
   else if(input_number>1000 && input_number<10000){
       int rem=input_number%100;
       int rem_two=rem%10;
       int quotient =rem/10;
       input_number=input_number/100;
       int thousand=input_number/10;
       int hundred = input_number%10;
       System.out.print(numbers_converter.get(thousand) + "thousand" + numbers_converter.get(hundred)+ " hundred");
       if(rem >0 && rem<20){
           System.out.print(numbers_converter.get(rem));
       }
       else if(rem >19 && rem <100){
           System.out.print(number_2nd.get(quotient) + numbers_converter.get(rem_two));
       }
   }
   else if(input_number>10000 && input_number<1000000000){
       //Say number 418,229,356
       int third_part=input_number%1000;//hold 356
       input_number=input_number/1000;//hold 418,229
       int sec_part=input_number%1000;//hold 229
       input_number=input_number/1000;// hold 418
       int rem_m=third_part%100;//hold 56
       int rem_m1=rem_m%10;//hold 6
       int rem_q=rem_m/10;// hold 5
       int q_m=third_part/100;// hold 3
       int sec_part_rem=sec_part%100;// hold 29
       int sec_part_rem1=sec_part_rem%10;//9
       int sec_part_q=sec_part_rem/10;//hold 2
       int sec_q=sec_part/100;// hold 2
       int input_q=input_number/100;// hold 4
       int input_rem=input_number%100;//hold 18
       int input_q_q=input_rem/10;//hold 1
       int input_rem1=input_rem%10;// hold 8
       System.out.print(numbers_converter.get(input_q) + " hundred ");
       if(input_rem>0 && input_rem<20){
           System.out.print(numbers_converter.get(input_rem)+ " Million ");
       }
       else{
           System.out.print(number_2nd.get(input_q_q) + " " + numbers_converter.get(input_rem1) + " Million ");
       }
       System.out.print(numbers_converter.get(sec_q) + " hundred ");
       if(sec_part_rem >0 && sec_part_rem<20){
           System.out.println(numbers_converter.get(sec_part_rem) + " thousand ");
       }
       else{
           System.out.print(number_2nd.get(sec_part_q) + " " + numbers_converter.get(sec_part_rem1) + " thousand ");
       }
       System.out.print(numbers_converter.get(q_m) + " hundred ");
       if(rem_m>0 && rem_m<20){
           System.out.print(numbers_converter.get(rem_m));
       }
       else{
           System.out.print(number_2nd.get(rem_q) + " " + numbers_converter.get(rem_m1));
       }
   }
  }
   }

Redundant Code Blocks

       int rem=input_number%100;
       int rem_two=rem%10;
       int quotient =rem/10;
       input_number=input_number/100;
       int thousand=input_number/10;
       int hundred = input_number%10;

This type of code block used almost every where. Taking a number divide it with 100 or 1000 to find out the hundred position then then divide it with 10 to find out the tenth position of the number. Finally using %(modular division) to find out the ones position.

How could I include user define function and switch case to minimize the code block.

Encipher
  • 1,370
  • 1
  • 14
  • 31
  • 2
    As your code is working fine (till millions) probably this question is more suitable for https://codereview.stackexchange.com??? – Ketan Dec 19 '18 at 23:19
  • A possible duplicate? https://stackoverflow.com/questions/3911966/how-to-convert-number-to-words-in-java – mmirwaldt Jan 19 '19 at 23:38

2 Answers2

1

Instead of storing the results in variables, use a method call:

int remainder100(int aNumber) {
    return aNumber % 100;
}

int remainder10(int aNumber) {
    return aNumber % 10;
}

...etc.

System.out.println(numbers_converter.get(remainder100(input_number)));

About 3rd problem: I wouldn't use switch ... case, too many cases.

Instead, take advantage that numbering repeats itself every 3 digits. That means the pattern for thousands and millions is the same (and billions, trillions, etc).

To do that, use a loop like this:

ArrayList<String> partialResult = new ArrayList<String>();
int powersOf1000 = 0;
for (int kiloCounter = input_number; kiloCounter > 0; kiloCounter /= 1000) {
    partialResult.add(getThousandsMilionsBillionsEtc(powersOf1000++);
    partialResult.add(convertThreeDigits(kiloCounter % 1000));
}

Then you can print out the contents of partialResult in reverse order to get the final number.

Perdi Estaquel
  • 819
  • 1
  • 6
  • 21
1

I'd suggest you break your single main method down into a couple of classes. And if you haven't already create a few unit tests to allow you to easily test / refactor things. You'll find it quicker than starting the app and reading from stdin.

You'll find it easier to deal with the number as a string. Rather than dividing by 10 all the time you just take the last character of the string. You could have a class that does that bit for you, and a separate one that does the convert.

Here's what I came up with, but I'm sure it can be improved. It has a PoppableNumber class which allows the last character of the initial number to be easily retrieved. And the NumberToString class which has a static convert method to perform the conversion.

An example of a test would be

@Test
public void Convert102356Test() {
    assertEquals("one hundred and two thousand three hundred and fifty six", NumberToString.convert(102356));
}

And here's the NumberToString class :

import java.util.HashMap;
import java.util.Map;

public class NumberToString {

    // billion is enough for an int, obviously need more for long
    private static String[] power3 = new String[] {"", "thousand", "million", "billion"};

    private static Map<String,String> numbers_below_twenty = new HashMap<String,String>();
    private static Map<String,String> number_tens = new HashMap<String,String>();

    static {
        numbers_below_twenty.put("0","");
        numbers_below_twenty.put("1","one");
        numbers_below_twenty.put("2","two");
        numbers_below_twenty.put("3","three");
        numbers_below_twenty.put("4","four");
        numbers_below_twenty.put("5","five");
        numbers_below_twenty.put("6","six");
        numbers_below_twenty.put("7","seven");
        numbers_below_twenty.put("8","eight");
        numbers_below_twenty.put("9","nine");
        numbers_below_twenty.put("10","ten");
        numbers_below_twenty.put("11","eleven");
        numbers_below_twenty.put("12","twelve");
        numbers_below_twenty.put("13","thirteen");
        numbers_below_twenty.put("14","fourteen ");
        numbers_below_twenty.put("15","fifteen");
        numbers_below_twenty.put("16","sixteen");
        numbers_below_twenty.put("17","seventeen");
        numbers_below_twenty.put("18","eighteen");
        numbers_below_twenty.put("19","nineteen");

        number_tens.put(null,"");
        number_tens.put("","");
        number_tens.put("0","");
        number_tens.put("2","twenty");
        number_tens.put("3","thirty");
        number_tens.put("4","forty");
        number_tens.put("5","fifty");
        number_tens.put("6","sixty");
        number_tens.put("7","seventy");
        number_tens.put("8","eighty");
        number_tens.put("9","ninty");
    }

    public static String convert(int value) {
        if (value == 0) {
            return "zero";
        }
        PoppableNumber number = new PoppableNumber(value);

        String result = "";
        int power3Count = 0;
        while (number.hasMore()) {
            String nextPart = convertUnitTenHundred(number.pop(), number.pop(), number.pop());
            nextPart = join(nextPart, " ", power3[power3Count++], true);
            result = join(nextPart, " ", result);
        }

        if (number.isNegative()) {
            result = join("minus", " ", result);
        }

        return result;
    }

    public static String convertUnitTenHundred(String units, String tens, String hundreds) {
        String tens_and_units_part = "";
        if (numbers_below_twenty.containsKey(tens+units)) {
            tens_and_units_part =  numbers_below_twenty.get(tens+units);
        }
        else {
            tens_and_units_part = join(number_tens.get(tens), " ", numbers_below_twenty.get(units));
        }
        String hundred_part = join(numbers_below_twenty.get(hundreds), " ", "hundred", true);
        return join(hundred_part, " and ", tens_and_units_part);
    }

    public static String join(String part1, String sep, String part2) {
        return join(part1, sep, part2, false);
    }

    public static String join(String part1, String sep, String part2, boolean part1Required) {
        if (part1 == null || part1.length() == 0) {
            return (part1Required) ? "" : part2;
        }
        if (part2.length() == 0) {
            return part1;
        }
        return part1 + sep + part2;

    }

    /**
     * 
     * Convert an int to a string, and allow the last character to be taken off the string using pop() method.
     * 
     * e.g.
     * 1432
     * Will give 2, then 3, then 4, and finally 1 on subsequent calls to pop().
     * 
     * If there is nothing left, pop() will just return an empty string.
     * 
     */
    static class PoppableNumber {

        private int original;
        private String number;
        private int start;
        private int next;


        PoppableNumber(int value) {
            this.original = value;
            this.number = String.valueOf(value);
            this.next = number.length();
            this.start = (value < 0) ? 1 : 0;   // allow for minus sign.
        }

        boolean isNegative() {
            return (original < 0);
        }

        boolean hasMore() {
            return (next > start);
        }

        String pop() {
            return hasMore() ? number.substring(--next, next+1) : "";
        }
    }

}
pcoates
  • 2,102
  • 1
  • 9
  • 20