Convert long number into abbreviated string in JavaScript, with a special shortness requirement

前端 未结 16 2180
名媛妹妹
名媛妹妹 2020-11-30 22:33

In JavaScript, how would one write a function that converts a given [edit: positive integer] number (below 100 billion) into a 3-letter abbreviation -- where 0-9 an

相关标签:
16条回答
  • 2020-11-30 22:52

    The modern, easy, built-in, highly customizable, and 'no-code' way: Intl.FormatNumber 's format function (compatibility graph)

    var numbers = [98721, 9812730,37462,29,093484620123, 9732,0283737718234712]
    for(let num of numbers){
      console.log(new Intl.NumberFormat( 'en-US', { maximumFractionDigits: 1,notation: "compact" , compactDisplay: "short" }).format(num));
    }
    98.7K
    9.8M
    37.5K
    29
    93.5B
    9.7K
    283.7T
    

    Notes:

    • If you're using typescript add a //@ts-ignore before notation (source)
    • And a list of all the keys in the options parameter: https://docs.w3cub.com/javascript/global_objects/numberformat/
    • When using style: 'currency', you must remove maximumFractionDigits, as it will figure this out for you.
    0 讨论(0)
  • 2020-11-30 22:53

    I believe ninjagecko's solution doesn't quite conform with the standard you wanted. The following function does:

    function intToString (value) {
        var suffixes = ["", "k", "m", "b","t"];
        var suffixNum = Math.floor((""+value).length/3);
        var shortValue = parseFloat((suffixNum != 0 ? (value / Math.pow(1000,suffixNum)) : value).toPrecision(2));
        if (shortValue % 1 != 0) {
            shortValue = shortValue.toFixed(1);
        }
        return shortValue+suffixes[suffixNum];
    }
    

    For values greater than 99 trillion no letter will be added, which can be easily fixed by appending to the 'suffixes' array.

    Edit by Philipp follows: With the following changes it fits with all requirements perfectly!

    function abbreviateNumber(value) {
        var newValue = value;
        if (value >= 1000) {
            var suffixes = ["", "k", "m", "b","t"];
            var suffixNum = Math.floor( (""+value).length/3 );
            var shortValue = '';
            for (var precision = 2; precision >= 1; precision--) {
                shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
                var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
                if (dotLessShortValue.length <= 2) { break; }
            }
            if (shortValue % 1 != 0)  shortValue = shortValue.toFixed(1);
            newValue = shortValue+suffixes[suffixNum];
        }
        return newValue;
    }
    
    0 讨论(0)
  • 2020-11-30 22:53

    Here's another take on it. I wanted 123456 to be 123.4K instead of 0.1M

    function convert(value) {
    
        var length = (value + '').length,
            index = Math.ceil((length - 3) / 3),
            suffix = ['K', 'M', 'G', 'T'];
    
        if (length < 4) return value;
        
        return (value / Math.pow(1000, index))
               .toFixed(1)
               .replace(/\.0$/, '') + suffix[index - 1];
    
    }
    
    var tests = [1234, 7890, 123456, 567890, 800001, 2000000, 20000000, 201234567, 801234567, 1201234567];
    for (var i in tests)
        document.writeln('<p>convert(' + tests[i] + ') = ' + convert(tests[i]) + '</p>');

    0 讨论(0)
  • 2020-11-30 22:55

    @nimesaram

    Your solution will not be desirable for the following case:

    Input 50000
    Output 50.0k
    

    Following solution will work fine.

    const convertNumberToShortString = (
      number: number,
      fraction: number
    ) => {
      let newValue: string = number.toString();
      if (number >= 1000) {
        const ranges = [
          { divider: 1, suffix: '' },
          { divider: 1e3, suffix: 'k' },
          { divider: 1e6, suffix: 'm' },
          { divider: 1e9, suffix: 'b' },
          { divider: 1e12, suffix: 't' },
          { divider: 1e15, suffix: 'p' },
          { divider: 1e18, suffix: 'e' }
        ];
        //find index based on number of zeros
        const index = Math.floor(Math.abs(number).toString().length / 3);
        let numString = (number / ranges[index].divider).toFixed(fraction);
        numString =
          parseInt(numString.substring(numString.indexOf('.') + 1)) === 0
            ? Math.floor(number / ranges[index].divider).toString()
            : numString;
        newValue = numString + ranges[index].suffix;
      }
      return newValue;
    };
    
    // Input 50000
    // Output 50k
    // Input 4500
    // Output 4.5k
    
    0 讨论(0)
  • 2020-11-30 22:56

    Based on my answer at https://stackoverflow.com/a/10600491/711085 , your answer is actually slightly shorter to implement, by using .substring(0,3):

    function format(n) {
        with (Math) {
            var base = floor(log(abs(n))/log(1000));
            var suffix = 'kmb'[base-1];
            return suffix ? String(n/pow(1000,base)).substring(0,3)+suffix : ''+n;
        }
    }
    

    (As usual, don't use Math unless you know exactly what you're doing; assigning var pow=... and the like would cause insane bugs. See link for a safer way to do this.)

    > tests = [-1001, -1, 0, 1, 2.5, 999, 1234, 
               1234.5, 1000001, Math.pow(10,9), Math.pow(10,12)]
    > tests.forEach(function(x){ console.log(x,format(x)) })
    
    -1001 "-1.k"
    -1 "-1"
    0 "0"
    1 "1"
    2.5 "2.5"
    999 "999"
    1234 "1.2k"
    1234.5 "1.2k"
    1000001 "1.0m"
    1000000000 "1b"
    1000000000000 "1000000000000"
    

    You will need to catch the case where the result is >=1 trillion, if your requirement for 3 chars is strict, else you risk creating corrupt data, which would be very bad.

    0 讨论(0)
  • 2020-11-30 22:56

    After some playing around, this approach seems to meet the required criteria. Takes some inspiration from @chuckator's answer.

    function abbreviateNumber(value) {
    
        if (value <= 1000) {
            return value.toString();
        }
    
        const numDigits = (""+value).length;
        const suffixIndex = Math.floor(numDigits / 3);
    
        const normalisedValue = value / Math.pow(1000, suffixIndex);
    
        let precision = 2;
        if (normalisedValue < 1) {
            precision = 1;
        }
    
        const suffixes = ["", "k", "m", "b","t"];
        return normalisedValue.toPrecision(precision) + suffixes[suffixIndex];
    }
    
    0 讨论(0)
提交回复
热议问题