How to format numbers like SO with C#?
10, 500, 5k, 42k, ...
How to format numbers like SO with C#?
10, 500, 5k, 42k, ...
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:
1231366,96823.1K133KNote that this will give strange values for numbers >= 108.
For example, 12345678 becomes 12.3KK.
The code below is tested up to int.MaxValue This is not the most beautiful code but is most efficient. But you can use it as:
123.KiloFormat(); 4332.KiloFormat(); 2332124.KiloFormat(); int.MaxValue.KiloFormat(); (int1 - int2 * int3).KiloFormat();
etc...
public static class Extensions
{
public static string KiloFormat(this int num)
{
if (num >= 100000000)
return (num / 1000000).ToString("#,0M");
if (num >= 10000000)
return (num / 1000000).ToString("0.#") + "M";
if (num >= 100000)
return (num / 1000).ToString("#,0K");
if (num >= 10000)
return (num / 1000).ToString("0.#") + "K";
return num.ToString("#,0");
}
}
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
I'm a bit late, but came up with this:
`private static List<Tuple<int, string>> ZeroesAndLetters = new List<Tuple<int, string>>()
{
new Tuple<int, string>(15, "Q"),
new Tuple<int, string>(12, "T"),
new Tuple<int, string>(9, "B"),
new Tuple<int, string>(6, "M"),
new Tuple<int, string>(3, "K"),
};
public static string GetPointsShortened(ulong num)
{
int zeroCount = num.ToString().Length;
for (int i = 0; i < ZeroesAndLetters.Count; i++)
if (zeroCount >= ZeroesAndLetters[i].Item1)
return (num / Math.Pow(10, ZeroesAndLetters[i].Item1)).ToString() + ZeroesAndLetters[i].Item2;
return num.ToString();
}`
In the ZeroesAndLetters list just add the numbers you need.
15, 12, 9 and ... are the number of zeroes, and Q, T, B and ... are shortened names.
Solution for C#8+
public static string ToKiloFormat(this int num)
{
return num switch
{
>= 100000000 => (num / 1000000D).ToString("0.#M"),
>= 1000000 => (num / 1000000D).ToString("0.##M"),
>= 100000 => (num / 1000D).ToString("0.#k"),
>= 10000 => (num / 1000D).ToString("0.##k"),
_ => num.ToString("#,0")
};
}
modified from a previous response
Something like this:
string formatted;
if (num >= 1000) {
formatted = ((double)num / 1000.0).ToString("N1") + "k";
} else {
formatted = num.ToString("N0");
}
If the number is bigger than some threshold, divide it by 1000 and then format it to however many decimal places you need.
int input = 12392; // for example
if (input >= 10000)
{
double thousands = input/1000.0;
Console.WriteLine(string.Format("{0}K", thousands));
}
This is moderately tested solution with rounding. It preserves meaningfulChars
digits after comma or dot and uses CultureInfo to determine the decimal delimiter.
As I was writing it I came to understanding that rounding is not needed in most cases. So if you need no rounding you'd better use something else or expand this solution.
I tried to ensure the precision will not got eaten by floating point arithmetics but I presume it may occur for really big numbers.
Also I believe this can be improved with IFormatProvider or similar intrinsic mechanism from .NET FW.
public static class ConversionUtilities {
class ConversionGroup {
public ConversionGroup(char symbol, long divider, int power) {
Symbol = symbol;
Divider = divider;
Power = power;
}
public char Symbol;
public long Divider;
public int Power;
}
private static ConversionGroup[] _conversionGroups = {
new ConversionGroup('k', 1000L, 3),
new ConversionGroup('m', 1000000L, 6),
new ConversionGroup('b', 1000000000L, 9)
};
/// <summary>
/// Converts integer value into string substituting 1 000 -> 1K, 1 000 000 -> 1M, 1 000 000 000 -> 1B
/// Rounds to meaingful chars
/// </summary>
/// <param name="value">value to convert</param>
/// <param name="meaninfulChars">round to that many characters after comma</param>
/// <param name="uppercase">when set K and M letters will be uppercase</param>
/// <returns></returns>
public static string ConvertIntToShortStringForm(long value, int meaninfulChars, bool uppercase) {
string ret = "";
long remainder = 0;
long fraction = 0;
char symbol = '\0';
int maxChars = meaninfulChars;
for (int i = _conversionGroups.Length - 1; i >= 0; i--) {
var group = _conversionGroups[i];
if (value >= group.Divider) {
if (meaninfulChars < 0) {
maxChars = 0;
}
else if (meaninfulChars > group.Power) {
maxChars = group.Power;
}
// int maxChars = Math.Clamp(meaninfulChars, 0, group.Power);
remainder = value % group.Divider;
if (remainder != 0) {
fraction = (long)Math.Round((double)remainder / (Math.Pow(10.0, (double)(group.Power - maxChars))));
if (maxChars == 0) {
if (value / group.Divider + fraction == 1000) {
if (i + 1 == _conversionGroups.Length) {
symbol = group.Symbol;
if (uppercase) {
symbol = Char.ToUpper(symbol);
}
return string.Format("{0}{1}", value / group.Divider + fraction + group.Symbol);
}
else {
symbol = _conversionGroups[i + 1].Symbol;
if (uppercase) {
symbol = Char.ToUpper(symbol);
}
return "1" + symbol;
}
} else {
ret += value / group.Divider + fraction;
}
}
else {
ret += value / group.Divider;
ret += CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
ret += fraction;
}
}
else {
ret += value / group.Divider;
}
symbol = group.Symbol;
if (uppercase) {
symbol = Char.ToUpper(symbol);
}
ret += symbol;
return ret;
}
}
return value.ToString();
}
}
Here is an example with truncation of the number and a max length of 6 characters for numbers smaller than 1 billion.
using System;
using System.Globalization;
class Program {
static void Main(string[] args)
{
int num = 0;
for(int i = 0; i < 9; i++)
{
int factor = i + 1;
num += (int)Math.Pow(10, i)*factor;
Console.WriteLine($"{num:N0} -> {num.ToStringShort()}");
}
num += (int)Math.Pow(10, 9);
Console.WriteLine($"{num:N0} -> {num.ToStringShort()}");
}
}
public static class NumberExtensions
{
public static string ToStringShort(this int num)
{
if(num < 1000)
{
return num.ToString("#0", CultureInfo.CurrentCulture);
}
if(num < 10000)
{
num /= 10;
return (num/100f).ToString("#.00'K'", CultureInfo.CurrentCulture);
}
if(num < 1000000)
{
num /= 100;
return (num/10f).ToString("#.0'K'", CultureInfo.CurrentCulture);
}
if(num < 10000000)
{
num /= 10000;
return (num/100f).ToString("#.00'M'", CultureInfo.CurrentCulture);
}
num /= 100000;
return (num/10f).ToString("#,0.0'M'", CultureInfo.CurrentCulture);
}
}
Output
1 -> 1
21 -> 21
321 -> 321
4,321 -> 4.32K
54,321 -> 54.3K
654,321 -> 654.3K
7,654,321 -> 7.65M
87,654,321 -> 87.6M
987,654,321 -> 987.6M
1,987,654,321 -> 1,987.6M
public static string KFormatter(long num)
{
if (num >= 1000000000) { return (num / 1000000000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "B"; }
if (num >= 1000000) { return (num / 1000000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "M"; }
if (num >= 10000) { return (num / 1000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "K"; }
return num.ToString("0,#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' });
}