11
\$\begingroup\$

Introduction:

Like Twitter and Instagram and others, I wanted to display numbers like 1.2K and 3.8 M instead of 1,222 or 3,823,456.

But that's not all! As we all know, there might be some human beings which undoubtely won't like these abbreviations and will try to reverse them. So, 1.2k will become 1,200 and 3.8 M will become 3,800,000.

The task:

  • your task is to write a program or a function that converts a list of numbers (which are given as strings) into their abbreviate pairs and vice-versa.

For example, if the input list (or any STDIN) was ['1.4k', '1,234,567', '7.99M'], then you should output:

['1,400', '1.2M', '7,990,000']

You can follow the next schema for abbreviations:

  • 103 -> one kilo -> K
  • 106 -> one million -> M
  • 109 -> one billion -> B

Your code may assume all lowercase, all uppercase, mixed case or undefined case for input and use any of these for output, but should be consistent.

Rules and restrictions:

  • you may write a program or function, taking input via STDIN (or closest alternative), command-line argument or function argument and outputting the result via STDOUT (or closest alternative), function return value or function (out) parameter.
  • input may be in any convenient list or string format. You may assume that the ai are less than 231 each and that the list contains at least one element.
  • each abbreviated number will contain only one . while a normal number will contain as many , as necessary (you may assume that this numbers won't be altered).
  • you MAY NOT enter a number as '123456' but rather 123,456
  • standard rules apply.

Test cases:

Input: ['1.5M', '77.6k', '123,456,789']         Output: ['1,500,000', '77,600', '123.4M']
Input: ['3,000,000,000', '581k', '2b']          Output: ['3B', '581,000', '2,000,000,000']
Input: ['0.1k']                                 Output: ['100']
Input: ['888', '33']                            Output: ['0.888k', '0.033k']

Clarifications:

  • for numbers < 1000 after the decimal point in abbreviation output you should have as many digits as required to get the correct result. (e.g: 2 -> will become 0.002k) - that means 3 decimals at most; for numbers > 1000 you can have a maximum of 1 decimal.
  • the abbreviation may be in both lower or upper case
  • I removed the built-ins restriction as suggested in the comments

The shortest code in bytes wins!

\$\endgroup\$
  • 1
    \$\begingroup\$ Requests for clarification: how many digits after the decimal point in abbreviation output? how to abbreviate numbers < 1000? uppercase or lowercase or both in input and output? \$\endgroup\$ – edc65 Nov 3 '16 at 12:07
  • 1
    \$\begingroup\$ Shouldn't '123,456,789' -> '123.4M'? Also, this doesn't clarify how many decimals to use. Surely anything under 1000 shouldn't need to be abbreviated anyways. \$\endgroup\$ – Kade Nov 3 '16 at 12:48
  • 1
    \$\begingroup\$ @anonymous2 read the third rule. \$\endgroup\$ – Grajdeanu Alex. Nov 3 '16 at 13:25
  • 4
    \$\begingroup\$ "you're not allowed to use any built-in module / function" Any built-in function? \$\endgroup\$ – Alex Howansky Nov 3 '16 at 14:12
  • 1
    \$\begingroup\$ Your usage of "kilo" suggests SI prefixes and those would be ["k", "M", "G"]. What does "while a normal number will contain as many , as necessary" mean, in my country it would be a mistake to use any. \$\endgroup\$ – Angs Nov 3 '16 at 14:31
2
\$\begingroup\$

PHP, 234 224 213 201 205 bytes

for(;$x=$argv[++$n];){$y=str_replace(",","",$x)/1e3;for($i=0;$y>999;$i++)$y=($y|0)/1e3;echo(A<$c=substr($x,strlen($x)-1))?number_format($x*[k=>1e3,m=>1e6,b=>1e9][$c]):($i?($y*10|0)/10:$y).kmb[$i]," ";}

6 bytes saved by insertusernamehere, 4 bytes inspired by that.


  • takes input from command line arguments, prints results space-separated with a trailing separator
  • expects lower case abbreviation
  • run with -r

-2 bytes if underscore as separator is ok: Replace " " with _.
-1 byte if correct rounding is ok: Replace ($y*10|0)/10 with round($y,1).
-17 bytes for PHP 7.1: Replace substr($x,strlen($x)-1) with $x[-1].


80 (63) bytes for expanding one argument only:

<?=number_format(($x=$argv[1])*[K=>1e3,M=>1e6,B=>1e9][substr($x,strlen($x)-1)]);

save to file, then execute (or replace <?= with echo+space and run with -r.

\$\endgroup\$
  • \$\begingroup\$ Your second example doesn't compile. \$\endgroup\$ – Alex Howansky Nov 3 '16 at 14:15
  • 1
    \$\begingroup\$ You have unbalanced parens. \$\endgroup\$ – Alex Howansky Nov 3 '16 at 14:17
  • 1
    \$\begingroup\$ -4 bytes: for($j=1;$x=$argv[$j++];) – instead of foreach($argv as$i=>$x)if($i) \$\endgroup\$ – insertusernamehere Nov 3 '16 at 17:05
  • 1
    \$\begingroup\$ -2 bytes: kmb[$i] – instead of "kmb"[$i]. \$\endgroup\$ – insertusernamehere Nov 3 '16 at 17:20
  • 1
    \$\begingroup\$ @insertusernamehere Negative string indexes are coming in PHP 7.1; and that´s a RC (yet). Thanks for the other bytes! \$\endgroup\$ – Titus Nov 4 '16 at 10:18
2
\$\begingroup\$

JavaScript, 545 524 522 518 514 508 504 498 494 214 bytes

Thanks to @ETHproductions for saving 180 bytes!

d=F=>F.map(f=>1/f.slice(-1)?f=(f=f.replace(/,/g,""))[9]?(f/1e8|0)/10+"B":f[6]?(f/1e5|0)/10+"M":f/1e3+"k":R(R(f.slice(0,-1)+"e"+' kMB'.indexOf(f.substr(-1))*3-0+"").match(/.{1,3}/g)+""),R=x=>[...x].reverse().join``)

To call the function:

d(["1.5M","1,500,000"]) //["1,500,500","1.5M"]

Outputs as alert, where each alert contains a different element of the input

Readable version:

d = F => F.map(f => 1 / f.slice(-1) ? f = (f = f.replace(/,/g, ""))[9] ? (f / 1e8 | 0) / 10 + "B" : f[6] ? (f / 1e5 | 0) / 10 + "M" : f / 1e3 + "k" : R(R(f.slice(0, -1) + "e" + ' kMB'.indexOf(f.substr(-1)) * 3 - 0 + "").match(/.{1,3}/g) + ""), R = x => [...x].reverse().join ``)

Summary of edits: converted function to an arrow function

  • removed semi-colons ';'
  • removed var
  • converted to an arrow function
  • used map to iterate through the individual elements of the array
  • used |0 instead of floor
  • used regex for testing
  • used ternary operators instead of if-else statements
  • included a separate function for .reverse().join''
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.