JS implementation of four digital kilogram formatting methods to share

Keywords: Javascript ECMAScript

The so-called digital thousandth form, that is, from the single digit, add a comma between every three digits. For example, "10000". To meet this requirement, I initially wrote such a function:

Method 1

The code is as follows:

// Method 1
function toThousands(num) {
    var result = [ ], counter = 0;
    num = (num || 0).toString().split('');
    for (var i = num.length - 1; i >= 0; i--) {
        counter++;
        result.unshift(num[i]);
        if (!(counter % 3) && i != 0) { result.unshift(','); }
    }
    return result.join('');
}

The execution process of method 1 is to convert the number into a string, break it up into an array, and then insert the elements in the array one by one into the beginning of the new array (result) from the end. Each time an element is inserted, the counter counts the number of times (plus 1). When the counter is a multiple of 3, a comma is inserted, but note that the beginning (when i is 0) does not need a comma. Finally, the result is obtained by calling the join method of the new array.
Method 1 is relatively clear and easy to understand, and has been used in the project for some time. But my intuition tells me that its performance is not good.

Method 2 - string version of method 1

The code is as follows:

//Method 2

function toThousands(num) {
    var result = '', counter = 0;
    num = (num || 0).toString();
    for (var i = num.length - 1; i >= 0; i--) {
        counter++;
        result = num.charAt(i) + result;
        if (!(counter % 3) && i != 0) { result = ',' + result; }
    }
    return result;
}

Method 2 is an improved version of method 1, which does not break the string into an array and always operates on the string.

Method 3 -- loop matching the last three numbers

The code is as follows:

// Method 3
function toThousands(num) {
    var num = (num || 0).toString(), re = /\d{3}$/, result = '';
    while ( re.test(num) ) {
        result = RegExp.lastMatch + result;
        if (num !== RegExp.lastMatch) {
            result = ',' + result;
            num = RegExp.leftContext;
        } else {
            num = '';
            break;
        }
    }
    if (num) { result = num + result; }
    return result;
}

The third method is a completely different algorithm. The three numbers at the end are matched through the regular expression loop. Each time, the comma and the matched content are inserted into the beginning of the result string, and then the matching target (num) is assigned to the content that has not been matched (RegExp.leftContext). Also note:

1. If the number of digits is a multiple of 3, the last matched content must be three digits, but there is no need to add a comma before the first three digits;
2. If the number of digits is not a multiple of 3, there must be 1 to 2 digits left in the num variable. After the loop, insert the remaining digits into the beginning of the result string.

Although method 3 reduces the number of cycles (three characters are processed in a cycle), it increases the consumption to a certain extent due to the use of regular expressions.

Method 4 - string version of method 3

The code is as follows:

// Method 4
function toThousands(num) {
    var num = (num || 0).toString(), result = '';
    while (num.length > 3) {
        result = ',' + num.slice(-3) + result;
        num = num.slice(0, num.length - 3);
    }
    if (num) { result = num + result; }
    return result;
}

In fact, the function of intercepting the last three characters can be achieved through the slice, substr or substring methods of string type. This avoids the use of regular expressions.

Method five -- combination and combination method

The code is as follows:

//Method 5

function toThousands(num) {
    var num = (num || 0).toString(), temp = num.length % 3;
    switch (temp) {
        case 1:
            num = '00' + num;
            break;
        case 2:
            num = '0' + num;
            break;
    }
    return num.match(/\d{3}/g).join(',').replace(/^0+/, '');
}

First, make up the number of digits of the number to a multiple of 3, cut it into a group of every three numbers through regular expression, then add commas through the join method, and finally remove the supplemented 0.

Method 6 - lazy method

The code is as follows:

// Method 6
function toThousands(num) {
    return (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
}

I've always thought that this format can be replaced by a regular expression, but I need to use assertions and other writing methods, but I'm not familiar with this part. After a while, Google really found such a regular expression, which is estimated to be the shortest implementation of the code.
test result

Time consumed for 5000 digital executions (ms)
Method 1 method 2 method 3 method 4 method 5 method 6
1 4 1 3 1 14 2
10 14 1 3 0 7 2
100 12 1 2 4 5 3
1000 13 2 3 2 9 5
10000 21 4 3 1 6 3
100000 21 3 2 1 5 6
The strong comparison between method 1 and method 2 shows that the efficiency of string operation is much higher than that of array operation; The test results of method 6 tell us that the length of code has nothing to do with the performance. The comprehensive performance of method 4 is the best (but why does the performance decrease when num is 100? This is really puzzling). The main reasons are:

1. Compare methods 1 and 2. Operate 3 characters each time instead of 1 character to reduce the number of cycles;
2. Compared with methods 3, 5 and 6, regular expressions are not used to reduce consumption.

Finally, I chose method 4 as the final optimization scheme. Readers can comment on better implementation methods or improvement suggestions.

Posted by airo on Mon, 06 Dec 2021 20:19:46 -0800