How to go about formatting 1200 to 1.2k in java How to go about formatting 1200 to 1.2k in java java java

How to go about formatting 1200 to 1.2k in java


Here is a solution that works for any long value and that I find quite readable (the core logic is done in the bottom three lines of the format method).

It leverages TreeMap to find the appropriate suffix. It is surprisingly more efficient than a previous solution I wrote that was using arrays and was more difficult to read.

private static final NavigableMap<Long, String> suffixes = new TreeMap<> ();static {  suffixes.put(1_000L, "k");  suffixes.put(1_000_000L, "M");  suffixes.put(1_000_000_000L, "G");  suffixes.put(1_000_000_000_000L, "T");  suffixes.put(1_000_000_000_000_000L, "P");  suffixes.put(1_000_000_000_000_000_000L, "E");}public static String format(long value) {  //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here  if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);  if (value < 0) return "-" + format(-value);  if (value < 1000) return Long.toString(value); //deal with easy case  Entry<Long, String> e = suffixes.floorEntry(value);  Long divideBy = e.getKey();  String suffix = e.getValue();  long truncated = value / (divideBy / 10); //the number part of the output times 10  boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);  return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;}

Test code

public static void main(String args[]) {  long[] numbers = {0, 5, 999, 1_000, -5_821, 10_500, -101_800, 2_000_000, -7_800_000, 92_150_000, 123_200_000, 9_999_999, 999_999_999_999_999_999L, 1_230_000_000_000_000L, Long.MIN_VALUE, Long.MAX_VALUE};  String[] expected = {"0", "5", "999", "1k", "-5.8k", "10k", "-101k", "2M", "-7.8M", "92M", "123M", "9.9M", "999P", "1.2P", "-9.2E", "9.2E"};  for (int i = 0; i < numbers.length; i++) {    long n = numbers[i];    String formatted = format(n);    System.out.println(n + " => " + formatted);    if (!formatted.equals(expected[i])) throw new AssertionError("Expected: " + expected[i] + " but found: " + formatted);  }}


I know, this looks more like a C program, but it's super lightweight!

public static void main(String args[]) {    long[] numbers = new long[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};    for(long n : numbers) {        System.out.println(n + " => " + coolFormat(n, 0));    }}private static char[] c = new char[]{'k', 'm', 'b', 't'};/** * Recursive implementation, invokes itself for each factor of a thousand, increasing the class on each invokation. * @param n the number to format * @param iteration in fact this is the class from the array c * @return a String representing the number n formatted in a cool looking way. */private static String coolFormat(double n, int iteration) {    double d = ((long) n / 100) / 10.0;    boolean isRound = (d * 10) %10 == 0;//true if the decimal part is equal to 0 (then it's trimmed anyway)    return (d < 1000? //this determines the class, i.e. 'k', 'm' etc        ((d > 99.9 || isRound || (!isRound && d > 9.99)? //this decides whether to trim the decimals         (int) d * 10 / 10 : d + "" // (int) d * 10 / 10 drops the decimal         ) + "" + c[iteration])         : coolFormat(d, iteration+1));}

It outputs:

1000 => 1k5821 => 5.8k10500 => 10k101800 => 101k2000000 => 2m7800000 => 7.8m92150000 => 92m123200000 => 123m9999999 => 9.9m


Here a solution that makes use of DecimalFormat's engineering notation:

public static void main(String args[]) {    long[] numbers = new long[]{7, 12, 856, 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};    for(long number : numbers) {        System.out.println(number + " = " + format(number));    }}private static String[] suffix = new String[]{"","k", "m", "b", "t"};private static int MAX_LENGTH = 4;private static String format(double number) {    String r = new DecimalFormat("##0E0").format(number);    r = r.replaceAll("E[0-9]", suffix[Character.getNumericValue(r.charAt(r.length() - 1)) / 3]);    while(r.length() > MAX_LENGTH || r.matches("[0-9]+\\.[a-z]")){        r = r.substring(0, r.length()-2) + r.substring(r.length() - 1);    }    return r;}

Output:

7 = 712 = 12856 = 8561000 = 1k5821 = 5.8k10500 = 10k101800 = 102k2000000 = 2m7800000 = 7.8m92150000 = 92m123200000 = 123m9999999 = 10m