23

I'd like to format following numbers into the numbers next to them with Android:

1000 to 1k 5821 to 5.8k 2000000 to 2m 7800000 to 7.8m

Mëd KB
  • 253
  • 1
  • 2
  • 4
  • 9
    Possible duplicate of [How to go about formatting 1200 to 1.2k in java](http://stackoverflow.com/questions/4753251/how-to-go-about-formatting-1200-to-1-2k-in-java) – Hiren Jungi Jan 25 '17 at 19:01
  • Try out this library https://github.com/tygalive/Number-Shortener [Disclaimer am the owner] – Richard Muvirimi Apr 06 '21 at 09:17

12 Answers12

25

Function

public String prettyCount(Number number) {
    char[] suffix = {' ', 'k', 'M', 'B', 'T', 'P', 'E'};
    long numValue = number.longValue();
    int value = (int) Math.floor(Math.log10(numValue));
    int base = value / 3;
    if (value >= 3 && base < suffix.length) {
        return new DecimalFormat("#0.0").format(numValue / Math.pow(10, base * 3)) + suffix[base];
    } else {
        return new DecimalFormat("#,##0").format(numValue);
    }
}

Use

prettyCount(789); Output: 789
prettyCount(5821); Output: 5.8k
prettyCount(101808); Output: 101.8k
prettyCount(7898562); Output: 7.9M
Ketan Ramani
  • 4,874
  • 37
  • 42
16

Try this method :

For Java

public static String formatNumber(long count) {
    if (count < 1000) return "" + count;
    int exp = (int) (Math.log(count) / Math.log(1000));
    return String.format("%.1f %c", count / Math.pow(1000, exp),"kMGTPE".charAt(exp-1));
}

For Kotlin(Android)

fun getFormatedNumber(count: Long): String {
if (count < 1000) return "" + count
val exp = (ln(count.toDouble()) / ln(1000.0)).toInt()
return String.format("%.1f %c", count / 1000.0.pow(exp.toDouble()), "kMGTPE"[exp - 1])
}
Ashav Kothari
  • 301
  • 3
  • 7
13

This should do the trick

String numberString = "";
if (Math.abs(number / 1000000) > 1) {
   numberString = (number / 1000000).toString() + "m";

} else if (Math.abs(number / 1000) > 1) {
   numberString = (number / 1000).toString() + "k";

} else {
   numberString = number.toString();

}
Garvit Jain
  • 1,862
  • 2
  • 19
  • 27
StackOverflower
  • 5,463
  • 13
  • 58
  • 89
  • 5
    Your logic will not show 1000 to 1k, because greater than equal to sign should be there. Also your logic will not show 5821 to 5.8k, it will show 5k instead of 5.8k. – Rahul Gupta Mar 17 '19 at 10:21
11

Try this trick:

 private String numberCalculation(long number) {
    if (number < 1000) 
        return "" + number;
    int exp = (int) (Math.log(number) / Math.log(1000));
    return String.format("%.1f %c", number / Math.pow(1000, exp), "kMGTPE".charAt(exp-1));
}
Tushar Lathiya
  • 940
  • 9
  • 26
  • Doesn't work with negative numbers – Psijic Sep 05 '22 at 15:16
  • Modified: ```fun compactNumber(number: Int): String { if (number in 0 until 1000) return number.toString() val exp = (ln(abs(number).toDouble()) / ln(1000.0)).toInt() return String.format("%.1f%c", number / 1000.0.pow(exp), "KMGTPE"[exp - 1]) }``` – Psijic Sep 05 '22 at 15:27
8

As of Android 7.0 (API 24), it is possible to use CompactDecimalFormat.

For example :

    private String convertNumber(int number, Locale locale) {
        CompactDecimalFormat compactDecimalFormat =
                CompactDecimalFormat.getInstance(locale, CompactDecimalFormat.CompactStyle.SHORT);
        return compactDecimalFormat.format(number);
    }

This class is also part of ICU v49 (https://unicode-org.github.io/icu-docs/apidoc/dev/icu4j/com/ibm/icu/text/CompactDecimalFormat.html).


Furthermore, as of Android 11 (API 30), it is possible to use NumberFormatter.

This class is also part of ICU v60.

Guillaume Husta
  • 4,049
  • 33
  • 40
3

// Kotlin Version

fun countviews(count:Long): String{
    val array = arrayOf(' ', 'k', 'M', 'B', 'T', 'P', 'E')
    val value = Math.floor(Math.log10(count.toDouble())).toInt()
    val  base = value / 3
        if (value >= 3 && base < array.size) {
            return DecimalFormat("#0.0").format(count/ Math.pow(10.0, (base * 3).toDouble())) + array[base]
        } else {
            return DecimalFormat("#,##0").format(count)
        }
    }
Kunal Mathur
  • 59
  • 1
  • 3
2

I needed to implement the same solution and took a hint from one of the answer in this thread. It suggested to use NumberFormatter for Android API 30+.

This is what is working for me. Additional benefit of using NumberFromatter API is that it adds the appropriate suffix as per Locale. Notation.compactShort() is the one adding engineering notations (K, M, B, T)

/**
 * Converts Number to appropriate rounded off format with max 1 decimal place
 * e.g. 1345 --> 1.3K, 15555900 --> 15.6M
*/
private fun formatCount(number: Long) = NumberFormatter.with()
    .notation(Notation.compactShort())
    .decimal(NumberFormatter.DecimalSeparatorDisplay.ALWAYS)
    .precision(Precision.fixedFraction(1))
    .locale(Resources.getSystem().configuration.locales.get(0))
    .format(number)
    .toString()
Wahib Ul Haq
  • 4,185
  • 3
  • 44
  • 41
1

This a Kotlin "extension on Double" that worked for me.
This also doesn't round the number:

fun Double.currencyCountWithSuffix(): String {
val suffixChars = "KMGTPE"
val formatter = DecimalFormat("###.#")
formatter.roundingMode = RoundingMode.DOWN

return if (this < 1000.0) formatter.format(this)
else {
    val exp = (ln(this) / ln(1000.0)).toInt()
    formatter.format(this / 1000.0.pow(exp.toDouble())) + suffixChars[exp - 1]
  }
}
Darshan
  • 4,020
  • 2
  • 18
  • 49
Fathallah
  • 91
  • 1
  • 3
0
public static String prettyCount(Double number) {
    DecimalFormat df = new DecimalFormat("#.#");
    String numberString = "";

    if (Math.abs(number / 1000000) >= 1) {
        numberString = df.format(number / 1000000.0) + "m";

    } else if (Math.abs(number / 1000.0) >= 1) {
        numberString = df.format(number / 1000.0) + "k";

    } else {
        numberString = number.toString();

    }
    return numberString;
}
RominaV
  • 3,335
  • 1
  • 29
  • 59
PintuBeast
  • 46
  • 3
0

Summary of all answers

private val Long.shortNotation
    get(): String {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val locale = AppCompatDelegate.getApplicationLocales()[0]
                ?: Resources.getSystem().configuration.locales.get(0)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) NumberFormatter.with()
                .notation(Notation.compactShort())
                .locale(locale)
                .format(this)
                .toString()
            else CompactDecimalFormat
                .getInstance(locale, CompactDecimalFormat.CompactStyle.SHORT)
                .format(this)
        } else {
            val base = 1_000f
            if (this < base) return "$this"
            val ratio = ln(this.toDouble()) / ln(base)
            val exp = ratio.toInt()
            val format = if (ratio % 1 * 3 < 1) "%.1f%c" else "%.0f%c"
            @Suppress("SpellCheckingInspection")
            String.format(format, this / base.pow(exp), "kMGTPE"[exp - 1])
        }
    }
k4dima
  • 6,070
  • 5
  • 41
  • 39
0

Simple use this function for kotlin

fun formatNumber(number: Long): String {
val suffix = charArrayOf(' ', 'k', 'M', 'B', 'T', 'P', 'E')
val value = floor(log10(number.toDouble())).toInt()
val base = value / 3
val result = if (value >= 3 && base < suffix.size) {
    DecimalFormat("#.#").format(
        number / 10.0.pow((base * 3).toDouble())
    ) + suffix[base]
} else {
    DecimalFormat("#,##0").format(number)
}
return result.convertToEnglishDigits()

}

Adam Noor
  • 101
  • 3
-1

This is a modified version of Sujith Manjavana answer.

here i have used DecimalFormat to control the integers after the decimal point.

long kil = 1000;
long meg = kil * 1000;
long gig = meg * 1000;
long ter = gig * 1000;

double bytes = 56789; // your integer. if you are using a String then -->  double bytes = Double.parseDouble(56789);
DecimalFormat form = new DecimalFormat("0.0"); // you can also use 0.00 or 0.000 


if ((bytes >= 0) && (bytes < kil)) {
String oneDecimal = form.format(bytes);
Toast.makeText(MainActivity.this, oneDecimal, Toast.LENGTH_LONG).show();

} else if ((bytes >= kil) && (bytes < meg)) {
    String oneDecimal = form.format(bytes / kil);
    Toast.makeText(MainActivity.this, oneDecimal+" K", Toast.LENGTH_LONG).show();
    
     } else if ((bytes >= meg) && (bytes < gig)) {
         String oneDecimal = form.format(bytes / meg);
         Toast.makeText(MainActivity.this, oneDecimal+" M", Toast.LENGTH_LONG).show();
         
         } else if ((bytes >= gig) && (bytes < ter)) {
             String oneDecimal = form.format(bytes / gig);
             Toast.makeText(MainActivity.this, oneDecimal+" B", Toast.LENGTH_LONG).show();
            
            } else if (bytes >= ter) {
                String oneDecimal = form.format(bytes / ter);
                Toast.makeText(MainActivity.this, oneDecimal+" T", Toast.LENGTH_LONG).show();
            } else {
                String oneDecimal = form.format(bytes);
                Toast.makeText(MainActivity.this, oneDecimal, Toast.LENGTH_LONG).show();
            }
HAZEEM JOONUS
  • 483
  • 6
  • 9