Padding numbers
We are sometimes faced with the need to pad numbers to a certain range. For example, suppose we want to display a number in five possible digits, such as 00042
. One obvious solution would be to use the iterative approach and prepend characters, but there are a few cleaner solutions.
Getting ready
First, we need to take a look at some of the functions that we are going to use. Let's take a look at the Array.join(separator)
method that can be applied to create joined text from a list of elements:
new Array('life','is','life').join('*')
This will result in "life*is*life"
that shows fairly simple elements that are joined with a given separator. Another method that is of interest is Array.slice(begin[, end])
that returns a copy of a portion of an array. For our use, we are only interested in the begin
parameter that can have both positive and negative values. If we use a positive value, it means that this will be the starting index for the slice using zero-based indexing; for example, consider the following line of code:
new Array('a','b','c','d','e','f','g').slice(4);
The preceding line of code will return an array with the elements 'e'
,'f'
, and 'g'
.
If, on the other hand, using a negative value for the begin
element indicates an offset from the end of the array, consider the same example using a negative value as follows:
new Array('a','b','c','d','e','f','g').slice(-3);
The result would be 'e','f','g'
, as we are slicing from the end.
How to do it...
Let's get back to our problem: how do we create a clean solution for prepending zeros to a number? For an iterative solution, we create a method that accepts the number, the size of the formatted result, and the character that will be used for padding; let's take '0'
for example:
function iterativeSolution(number,size,character) { var strNumber = number.toString(), len = strNumber.length, prefix = ''; for (var i=size-len;i>0;i--) { prefix += character; } return prefix + strNumber; }
Here we converted the number to a string in order to get the length of its representation; afterwards, we simply create prefix
that will have the size–len
characters of the character
variable, and just return the resulting prefix + strNumber
that is the string representation for that number.
You may notice that in the case where size
is smaller than len
, the original number is returned, and this should probably be changed in order to have the function working for that corner case.
Another way would be to use the Array.slice()
method to achieve similar results:
function sliceExample(number,prefix){ return (prefix+number).slice(-prefix.length); } sliceExample(42,"00000");
This will just prepend a prefix to a number and slice off the extra '0'
counting from the end, making the solution a lot cleaner and, additionally, enabling us to be more flexible around what will be part of the prefix. The downside of this is that we are manually constructing the prefix that will be part of the method call sliceExample(42,"00000")
. In order to make this process automatic, we can make use of Array.join
:
function padNumber(number,size,character){ var prefix = new Array(1 + size).join(character);
We create an array of the expected size + 1
as on joining, we'll get the total array size-1 joined elements
. This will construct the prefix with the expected size, and the other part will remain the same:
return (prefix + number).slice(-prefix.length); }
A sample method call will be padNumber(42,5,'0')
; this will not have the flexibility of the previous method, but it will be a lot simpler to use in larger numbers.
How it works…
The recipe is fairly straightforward, but an important thing to note is the functional approach. If there is one thing to take with you from this recipe, it is that the iterative solution is not always the best. When it comes to JavaScript, there are usually a few other ways to complete the task that you have; they are not always that straightforward and sometimes not even faster, but they can be much cleaner.
There's more...
If, for some reason, we are padding numbers very often, it might make sense to add the function into the Number
object and remove the input
parameter number with the this
keyword:
Number.prototype.pad=function(size,character){ //same functionality here }
As the function is now part of every Number
object, we can use it directly from any number; let's take the following example:
3.4.pad(5,'#');
Additionally, if the '.'
character should not be included in the calculation of the padding, we could add an additional check that would reduce the size of the prefix.
Note
Note that in the Rounding numbers for display recipe, we explained why adding functions to a standard object is a hack that can backfire at us.