Format Number like Stack Overflow (rounded to thousands with K suffix)

34,244

Solution 1

Like this: (EDIT: Tested)

static string FormatNumber(int num) {
    if (num >= 100000)
        return FormatNumber(num / 1000) + "K";

    if (num >= 10000)
        return (num / 1000D).ToString("0.#") + "K";

    return num.ToString("#,0");
}

Examples:

  • 1 => 1
  • 23 => 23
  • 136 => 136
  • 6968 => 6,968
  • 23067 => 23.1K
  • 133031 => 133K

Note that this will give strange values for numbers >= 108.
For example, 12345678 becomes 12.3KK.

Solution 2

You can crate a CustomFormater like this:

public class KiloFormatter: ICustomFormatter, IFormatProvider
{
    public object GetFormat(Type formatType)
    {
        return (formatType == typeof(ICustomFormatter)) ? this : null;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
        if (format == null || !format.Trim().StartsWith("K")) {
            if (arg is IFormattable) {
                return ((IFormattable)arg).ToString(format, formatProvider);
            }
            return arg.ToString();
        }

        decimal value = Convert.ToDecimal(arg);

        //  Here's is where you format your number

        if (value > 1000) {
            return (value / 1000).ToString() + "k";
        }

        return value.ToString();
    }
}

And use it like this:

String.Format(new KiloFormatter(), "{0:K}", 15600);

edit: Renamed CurrencyFormatter to KiloFormatter

Solution 3

A slightly modified version of SLaks code

static string FormatNumber(long num)
{
    if (num >= 100000000) {
        return (num / 1000000D).ToString("0.#M");
    }
    if (num >= 1000000) {
        return (num / 1000000D).ToString("0.##M");
    }
    if (num >= 100000) {
        return (num / 1000D).ToString("0.#k");
    }
    if (num >= 10000) {
        return (num / 1000D).ToString("0.##k");
    }

    return num.ToString("#,0");
}

This will return the following values:

 123        ->  123
 1234       ->  1,234
 12345      ->  12.35k
 123456     ->  123.4k
 1234567    ->  1.23M
 12345678   ->  12.35M
 123456789  ->  123.5M

Solution 4

I just wrote some to provide complete information

public static class SIPrefix
{
    private static List<SIPrefixInfo> _SIPrefixInfoList = new
        List<SIPrefixInfo>();

    static SIPrefix()
    {
        _SIPrefixInfoList = new List<SIPrefixInfo>();
        LoadSIPrefix();
    }

    public static List<SIPrefixInfo> SIPrefixInfoList
    { 
        get 
        { 
            SIPrefixInfo[] siPrefixInfoList = new SIPrefixInfo[6];
            _SIPrefixInfoList.CopyTo(siPrefixInfoList);
            return siPrefixInfoList.ToList();
        }
    }

    private static void LoadSIPrefix()
    {
        _SIPrefixInfoList.AddRange(new SIPrefixInfo[]{
            new SIPrefixInfo() {Symbol = "Y", Prefix = "yotta", Example = 1000000000000000000000000.00M, ZeroLength = 24, ShortScaleName = "Septillion", LongScaleName = "Quadrillion"},
            new SIPrefixInfo() {Symbol = "Z", Prefix = "zetta", Example = 1000000000000000000000M, ZeroLength = 21, ShortScaleName = "Sextillion", LongScaleName = "Trilliard"},
            new SIPrefixInfo() {Symbol = "E", Prefix = "exa", Example = 1000000000000000000M, ZeroLength = 18, ShortScaleName = "Quintillion", LongScaleName = "Trillion"},
            new SIPrefixInfo() {Symbol = "P", Prefix = "peta", Example = 1000000000000000M, ZeroLength = 15, ShortScaleName = "Quadrillion", LongScaleName = "Billiard"},
            new SIPrefixInfo() {Symbol = "T", Prefix = "tera", Example = 1000000000000M, ZeroLength = 12, ShortScaleName = "Trillion", LongScaleName = "Billion"},
            new SIPrefixInfo() {Symbol = "G", Prefix = "giga", Example = 1000000000M, ZeroLength = 9, ShortScaleName = "Billion", LongScaleName = "Milliard"},
            new SIPrefixInfo() {Symbol = "M", Prefix = "mega", Example = 1000000M, ZeroLength = 6, ShortScaleName = "Million", LongScaleName = "Million"},
            new SIPrefixInfo() {Symbol = "K", Prefix = "kilo", Example = 1000M, ZeroLength = 3, ShortScaleName = "Thousand", LongScaleName = "Thousand"},
            new SIPrefixInfo() {Symbol = "h", Prefix = "hecto", Example = 100M, ZeroLength = 2, ShortScaleName = "Hundred", LongScaleName = "Hundred"},
            new SIPrefixInfo() {Symbol = "da", Prefix = "deca", Example = 10M, ZeroLength = 1, ShortScaleName = "Ten", LongScaleName = "Ten"},
            new SIPrefixInfo() {Symbol = "", Prefix = "", Example = 1M, ZeroLength = 0, ShortScaleName = "One", LongScaleName = "One"},
        });
    }

    public static SIPrefixInfo GetInfo(long amount, int decimals)
    {
        return GetInfo(Convert.ToDecimal(amount), decimals);
    }

    public static SIPrefixInfo GetInfo(decimal amount, int decimals)
    {
        SIPrefixInfo siPrefixInfo = null;
        decimal amountToTest = Math.Abs(amount);

        var amountLength = amountToTest.ToString("0").Length;
        if(amountLength < 3)
        {
            siPrefixInfo = _SIPrefixInfoList.Find(i => i.ZeroLength == amountLength).Clone() as SIPrefixInfo;
            siPrefixInfo.AmountWithPrefix =  Math.Round(amount, decimals).ToString();

            return siPrefixInfo;
        }

        siPrefixInfo = _SIPrefixInfoList.Find(i => amountToTest > i.Example).Clone() as SIPrefixInfo;

        siPrefixInfo.AmountWithPrefix = Math.Round(
            amountToTest / Convert.ToDecimal(siPrefixInfo.Example), decimals).ToString()
                                        + siPrefixInfo.Symbol;

        return siPrefixInfo;
    }
}

public class SIPrefixInfo : ICloneable
{
    public string Symbol { get; set; }
    public decimal Example { get; set; }
    public string Prefix { get; set; }
    public int ZeroLength { get; set; }
    public string ShortScaleName { get; set; }
    public string LongScaleName { get; set; }
    public string AmountWithPrefix { get; set; }

    public object Clone()
    {
        return new SIPrefixInfo()
                            {
                                Example = this.Example,
                                LongScaleName = this.LongScaleName,
                                ShortScaleName = this.ShortScaleName,
                                Symbol = this.Symbol,
                                Prefix = this.Prefix,
                                ZeroLength = this.ZeroLength
                            };

    }
}

Use:

var amountInfo = SIPrefix.GetInfo(10250, 2);
var amountInfo2 = SIPrefix.GetInfo(2500000, 0);

amountInfo.AmountWithPrefix // 10.25K
amountInfo2.AmountWithPrefix // 2M

Solution 5

I wrote this method to minify long numbers:

public string minifyLong(long value)
    {
        if (value >= 100000000000)
            return (value / 1000000000).ToString("#,0") + " B";
        if (value >= 10000000000)
            return (value / 1000000000D).ToString("0.#") + " B";
        if (value >= 100000000)
            return (value / 1000000).ToString("#,0") + " M";
        if (value >= 10000000)
            return (value / 1000000D).ToString("0.#") + " M";
        if (value >= 100000)
            return (value / 1000).ToString("#,0") + " K";
        if (value >= 10000)
            return (value / 1000D).ToString("0.#") + " K";
        return value.ToString("#,0"); 
    }
Share:
34,244
Bechi
Author by

Bechi

Updated on October 19, 2021

Comments

  • Bechi
    Bechi over 2 years

    How to format numbers like SO with C#?

    10, 500, 5k, 42k, ...

  • Daniel Earwicker
    Daniel Earwicker over 14 years
    That would print 36k for your rep, not 36.8k. StackOverflow's version keeps some significant figures.
  • DOK
    DOK over 14 years
    What does that return for display?
  • DOK
    DOK over 14 years
    What does that return for, say, Earwicker's 12392?
  • DOK
    DOK over 14 years
    @SLaks: Sweet! You might consider editing your answer to include this example.
  • Michael Greene
    Michael Greene over 14 years
    if (num >= 100000000) return FormatNumber(num / 1000000) + "M"; fixes the note of course.
  • Alex LE
    Alex LE over 14 years
    @DOK: This is the standard way of creating reusable Formatters in the .NET Framework
  • DOK
    DOK over 14 years
    Um, I don't see how the arguments in your example of how to call the Format method match up with the method's signature. new Kiloformatter() isn't a string, "{0:K}" could be an object, 15600 isn't an IFormatProvider. Perhaps you need to edit your answer?
  • SLaks
    SLaks over 14 years
    @DOK: His example is correct. msdn.microsoft.com/en-us/library/1ksz8yb7.aspx
  • DOK
    DOK over 14 years
    @SLaks: really? String.Format(new KiloFormatter(), "{0:K}", 15600); matches up to the method signature Format(string, object, IFormatProvider)?
  • SLaks
    SLaks over 14 years
    @DOK: Read it again: public static string Format( IFormatProvider provider, string format, params Object[] args)
  • DOK
    DOK over 14 years
    @SLaks: I am reading his Format method above: public string Format(string format, object arg, IFormatProvider formatProvider) That is not what is being called?
  • SLaks
    SLaks over 14 years
    He's calling String.Format, not new KilFormatter().Format.
  • Justin Grant
    Justin Grant over 13 years
    @SLaks - this code breaks for values like 133987 due to truncation instead of rounding. Expected: 134K. Actual: 133K. You can fix the problem by adding 500 to num before dividing by 1000, e.g. FormatNumber( (num+500) / 1000) + "K"
  • Chandan Kumar
    Chandan Kumar almost 6 years
    What about Lakhs? how to get it?
  • Cruiser KID
    Cruiser KID almost 6 years
    Between kilo and mega you can add lakh with new SIPrefixInfo() {Symbol = "L", Prefix = "Lakh", Example = 100000M, ZeroLength = 5, ShortScaleName = "Lakh", LongScaleName = "Lakh"},
  • Erik Thysell
    Erik Thysell almost 5 years
    Very nice.. the only thing we lack is the smaller postfix (which I guess it should be called instead of "pre" even you you prenounce it before the value you put it after in written form but I guess that is another discussion.. :) .... (deci, centi, milli, micro, nano, pico, femto, atto, zepto, yocto ... ) it would be nice if this was in the c# core or something like that...
  • Arad
    Arad over 4 years
    This is exactly what I needed. Thanks.