Sanstech

Ideas, Knowledge, Technology, Computer Science, Experience associated with my work and some geeky stuff I progressively encounter during my journey towards enlightenment. Read on…

  • RSS RSS Feed

    • Cloud Computing
      It’s been really long, since I last wrote a tech post. In this post, I’m just sharing few useful links to get started on Cloud Computing, whether you’re a developer, quality engineer, business leader, or a project manager intending to get started with Cloud Computing. I’m currently designing systems and services, for a platform that’s […]
    • The Pragmatic Programmer
      I finished reading The Pragmatic Programmer by Andrew Hunt and David Thomas. It’s not a new book in the market but I was curious to read this. The technology topics covered, are not any different from those found in most software engineering books, but the way they’re presented using Pragmatic Philosophy Approach, is remarkable. Code […]
    • 2013 in review
      The WordPress.com stats helper monkeys prepared a 2013 annual report for this blog. Here’s an excerpt: A San Francisco cable car holds 60 people. This blog was viewed about 1,200 times in 2013. If it were a cable car, it would take about 20 trips to carry that many people. Click here to see the […]
    • Goodbye, Ness!
      It had to happen sometime. I thought Feb 2013 was the right time. I quit Ness after a long 5 years and 4 months of stay, in Feb. I joined FICO (formerly, Fair Isaac) last Feb.  While I get an opportunity to work with many varied stakeholders like Scientists, Architect, Product Management, Peer Developers, PMO, Technical Publications and also […]
    • Meta: information retrieval from Tweets
      I pick significant problems randomly sometimes and enjoy solving them, or at least attempt designing api :-). Here’s one such problem! Problem: How’d you go about finding meta information about a person’s tweets? NOTE: a) Tweet == Twitter updates b) Meta information –> Loosely defined. You can interpret it anyway you want –> Frequency, topics, follower […]
  • Twitter Updates

Number to Text Representation Problem

Posted by sanstechbytes on April 22, 2012

Problem:

Given a number (up to a billion), display the string (text) representation of it. For eg.: 123456789 should be represented as “One Hundred and Twenty Three Million Four Hundred and Fifty Six thousand Seven Hundred and Eighty Nine. ‘and’ should only be used after hundred.

Solution:

Approach 1: In a OO approach, a number can be represented by Number class. Each Number object has a list of Triplet objects (composition). Triplet represents a group of max 3 digits and can’t exist without a Number.  With this approach, it’s easy to accommodate different text representation systems like British English International Unit (million etc), British English Indian Units (lac, crore).

I wrote the classes (see below) for both approaches including JUnit Tests. I’ve captured the outputs for sample runs in the project folder that you can download here.

Approach 2: Assume Text representation in British English. Think of converting 123456789 into “One Hundred and Twenty Three Million Four Hundred and Fifty Six thousand Seven Hundred and Eighty Nine.

So, convert(123456789) = convert(123) + “million” + convert(456) + “thousand” + convert(789). [Courtesy: Gayle Laakmann of careercup.com]. This makes use of the technique of recursion. A lot of new code has to be written to extend this behavior though. There’re too many special cases to handle.

Code: Approach 1:


package numbertextoop;

import java.util.LinkedList;
import java.util.List;

import utils.NumberTextUtils;

/**
* This class represents a given number. Can be used to display in British
* English phrase the number Eg: 1234 in British English phrase: One Thousand
* Two Hundred and Thirty Four This class can accommodate text representation
* types like British, Indian etc with the constructor provided 04/14/2012 @author
* sanjeev 04/19/2012 @author sanjeev
*
* @version 1.1
*/

public class Number {

private int num;
private List<Triplet> triplets;

/**
* Assume default text representation type as British
*/
public Number(int i) {

this.num = i;

/**
* Handle negative number
*/
if (i < 0) {
i = -1 * i;
}

int length = Integer.toString(i).length();

if (length % NumberTextUtils.THREE == 0) {
length = length / NumberTextUtils.THREE;
} else if (length % NumberTextUtils.THREE > 0) {
length = length / NumberTextUtils.THREE + 1;
}

this.triplets = new LinkedList<Triplet>();
buildTriplets(i, length);
}

/**
* Allows for specifying text representation system, British, Indian etc
* text representationType could be enum - TextRepresentationType.BRITISH,
* TextRepresentationType.INDIAN. In Case of 'Indian', constants like Lac,
* Crore, should be added appropriately in NumberTextUtils.java
*/
public Number(int i, String representationType) {

}

/**
* @param num
* @param length
*            Builds triplet objects and arranges the position (hundredth,
*            tenth, unit) of the digits forming a triplet
*/
private void buildTriplets(int num, int length) {
while (length != 0) {
int tripletValue = num % 1000;

Triplet triplet = new Triplet(tripletValue);
triplet = triplet.matchTripletPlaces(tripletValue);

System.out.println("triplet" + triplet.getHundredthPlace() + "."
+ triplet.getTenthPlace() + ":" + triplet.getUnitPlace());
((LinkedList<Triplet>) this.triplets).addFirst(triplet);

num = num / NumberTextUtils.THOUSAND;
length--;
}
}

/**
* String representation of this number
*
*/
public String toString() {

/**
* When num = 0, returns "Zero" or if accessed thro
*
*/
if (this.num == 0) {
return NumberTextUtils.ZERO_TEXT;
}

StringBuilder numTextBuilder = new StringBuilder();

/**
* Negative number
*
*/
if (this.num < 0) {
numTextBuilder.append("Negative ");
}

return constructEnglishText(this.triplets, numTextBuilder).toString();
}

/**
* Constructs the British English text from this group of triplets formed
* from
*
* @param num
* @param triplets
*            List
*/
private StringBuilder constructEnglishText(List<Triplet> triplets,
StringBuilder numTextBuilder) {
int mapIndex = triplets.size();

for (Triplet triplet : triplets) {
numTextBuilder = numTextBuilder.append(triplet.toString()).append(
" ");

/**
* When num = 1,000,000: print only one million
*/
if (triplet.getHundredthPlace() == 0
&& triplet.getTenthPlace() == 0
&& triplet.getUnitPlace() == 0
&& mapIndex < this.triplets.size()) {
numTextBuilder = numTextBuilder.append("");
} else {
numTextBuilder = numTextBuilder.append(
NumberTextUtils.tripletMap().get(mapIndex)).append(" ");
}

mapIndex--;
}

return numTextBuilder;
}

public int getNum() {
return num;
}

public String getText() {
return this.toString();
}

public List<Triplet> getTriplets() {
return triplets;
}

}

 

package numbertextoop;

import utils.NumberTextUtils;

/**
* This class represents a group of digits up to a maximum of 3 that form a
* given number. 04/14/12 @author sanjeev 04/19/12 @author sanjeev
*
* @version 1.1
*/
public class Triplet {

private int hundredthPlace;
private int tenthPlace;
private int unitPlace;
private int value;

public Triplet(int tripletGroupNum) {
this.value = tripletGroupNum;
}

/**
* Arranges the place of digits for hundredth, tenth and unit positions in
* this triplet
*
* @param tripletValue
* @return Triplet
*/
public Triplet matchTripletPlaces(int tripletValue) {
this.setHundredthPlace(tripletValue / NumberTextUtils.HUNDRED);

tripletValue = tripletValue % NumberTextUtils.HUNDRED;
this.setTenthPlace(tripletValue / NumberTextUtils.TEN);

tripletValue = tripletValue % NumberTextUtils.TEN;
this.setUnitPlace(tripletValue);

return this;
}

/**
* Returns the string representation of this triplet
*
* @see java.lang.Object#toString()
*/
public String toString() {
return constructTripletText().toString();
}

/**
* @return tripletText StringBuilder
*/
private StringBuilder constructTripletText() {

StringBuilder tripletText = new StringBuilder();

tripletText = appendHundredthPlaceText(tripletText);

/** 'Teen' candidate check: 13 -> Thirteen, 11 -> Eleven */
StringBuilder teenCandidateBuilder = new StringBuilder();
String teenCandidate = teenCandidateBuilder.append(
String.valueOf(this.tenthPlace)).append(
String.valueOf(this.unitPlace)).toString();
int teenCandidateValue = Integer.parseInt(teenCandidate);

tripletText = appendTenthPlaceText(tripletText, teenCandidateValue);

tripletText = appendUnitPlaceText(tripletText, teenCandidateValue);

return tripletText;
}

/**
* Unit place text candidates Unit place : Five, Zero, Two etc
*/
private StringBuilder appendUnitPlaceText(StringBuilder tripletText,
int teenCandidate) {
/** Print unit place text: 1 -> one, 9 -> nine etc */
if (this.unitPlace != 0) {
if (isATeenNumber(teenCandidate)) {
return tripletText;
}

tripletText = appendDigitText(tripletText, this.unitPlace);
}

return tripletText;
}

/**
* Tenth place and 'Teen' text candidates Tenth place : Five, Eleven,
* Thirteen etc.
*/
private StringBuilder appendTenthPlaceText(StringBuilder tripletText,
int teenCandidate) {
if (this.tenthPlace != 0) {
if (isATeenNumber(teenCandidate)) {
tripletText = tripletText
.append(NumberTextUtils.teens[this.unitPlace]);
} else {
tripletText = tripletText
.append(NumberTextUtils.tens[this.tenthPlace - 1]);
}
tripletText.append(" ");
}

return tripletText;
}

/**
* Hundredth place text candidates Hundredth place : Two Hundred, Two
* Hundred and etc.
*/
private StringBuilder appendHundredthPlaceText(StringBuilder tripletText) {
if (this.hundredthPlace != 0) {
if (this.tenthPlace == 0 && this.unitPlace == 0) {
tripletText = appendDigitText(tripletText, this.hundredthPlace)
.append(" Hundred ");
} else {
tripletText = appendDigitText(tripletText, this.hundredthPlace)
.append(" Hundred and ");
}
}

return tripletText;
}

/**
* @param tripletText
* @param digit
* @return
*/
public StringBuilder appendDigitText(StringBuilder tripletText, int digit) {
tripletText.append(NumberTextUtils.digits[digit]);
return tripletText;
}

/**
* @param teenCandidate
* @return true if the number belongs to [11, 12, 13, 14, 15, 16, 17, 18,
*         19]
*/
public boolean isATeenNumber(int teenCandidate) {
return (teenCandidate >= NumberTextUtils.ELEVEN && teenCandidate < NumberTextUtils.TWENTY);
}

public int getValue() {
return value;
}

public int getHundredthPlace() {
return hundredthPlace;
}

public void setHundredthPlace(int hundredthPlace) {
this.hundredthPlace = hundredthPlace;
}

public int getTenthPlace() {
return tenthPlace;
}

public void setTenthPlace(int tenthPlace) {
this.tenthPlace = tenthPlace;
}

public int getUnitPlace() {
return unitPlace;
}

public void setUnitPlace(int unitPlace) {
this.unitPlace = unitPlace;
}

}

Code: Approach 2:

package numbertextalgo;

import utils.NumberTextUtils;

/**
* This class represents a given number in British English phrase Eg: 1234 in
* British English phrase: One Thousand Two Hundred and Thirty Four
*
* @author sanjeev, 14-Apr-2012
* @version 1.0
*/

public class NumberText {

public NumberText() {

}

public static String numberToString(int number) {
if (number == 0) {
return NumberTextUtils.ZERO_TEXT;
} else if (number < 0) {
return NumberTextUtils.NEGATIVE_TEXT + numberToString(-1 * number);
}

int count = 0;
String str = "";

while (number > 0) {
if (number % NumberTextUtils.THOUSAND != 0) {
str = numberToString100(number % NumberTextUtils.THOUSAND)
+ NumberTextUtils.bigs[count] + " " + str;
number /= NumberTextUtils.THOUSAND;
count++;
}
}

return str;
}

private static String numberToString100(int number) {
String str = "";

/** Convert hundredth place */
if (number >= NumberTextUtils.HUNDRED) {
str += NumberTextUtils.digits[number / NumberTextUtils.HUNDRED - 1]
+ " Hundred and ";
number %= NumberTextUtils.HUNDRED;
}

/** Convert NumberTextUtils.tens place */
if (number >= NumberTextUtils.ELEVEN
&& number <= NumberTextUtils.NINETEEN) {
return str + NumberTextUtils.teens[number - NumberTextUtils.ELEVEN]
+ " ";
} else if (number == NumberTextUtils.TEN
|| number >= NumberTextUtils.TWENTY) {
str += NumberTextUtils.tens[number / NumberTextUtils.TEN - 1] + " ";
number %= NumberTextUtils.TEN;
}

/** Convert ones place */
if (number >= NumberTextUtils.ONE && number <= NumberTextUtils.NINE) {
str += NumberTextUtils.digits[number - 1] + " ";
}

return str;
}
}

 

package utils;

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

/**
* This class is used as a utility class for representing a number in text
* 04/14/12 @author sanjeev 04/19/12 @author sanjeev
*
* @version 1.1
*/
public class NumberTextUtils {

public static String[] digits = new String[] { "Zero", "One", "Two",
"Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" };
public static String[] teens = new String[] { "", "Eleven", "Twelve",
"Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen",
"Eighteen", "Nineteen" };
public static String[] tens = new String[] { "Ten", "Twenty", "Thirty",
"Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety" };
public static String[] bigs = new String[] { "", "Thousand", "Million",
"Billion" };

public static final String NEGATIVE_TEXT = "Negative";
public static final String ZERO_TEXT = "Zero";

public static final int ONE = 1;
public static final int THREE = 3;
public static final int NINE = 9;
public static final int TEN = 10;
public static final int TWENTY = 20;
public static final int ELEVEN = 11;
public static final int NINETEEN = 19;
public static final int HUNDRED = 100;
public static final int THOUSAND = 1000;

public static Map<Integer, String> tripletGroupMap = new HashMap<Integer, String>();

static {
tripletGroupMap.put(1, "");
tripletGroupMap.put(2, "Thousand");
tripletGroupMap.put(3, "Million");
tripletGroupMap.put(4, "Billion");
}

public static Map<Integer, String> tripletMap() {
return tripletGroupMap;
}
} 

 

package numbertextoop;

/**
* Test Class with main() for Number.java
*
* @author sanjeev
*
*/
public class TestNumber {

public static void main(String[] args) {
int num = 1000000000;
Number number = new Number(num);

sop(num + " in British English Phrase using OOP: " + number.getText());
}

private static void sop(Object o) {
System.out.println(o);
}

}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: