Skip to content

alternate implementation, support decimals, extra tests, benchmarking #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
test
benchmark/
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ var commaNumber = require('comma-number')
commaNumber(1000) // "1,000"
commaNumber(-1000) // "-1,000"
commaNumber(-1000, '.') // "-1.000"

commaNumber(1000.12) // "1,000.12"
commaNumber(-1000.12) // "-1,000.12"
commaNumber('-1000,12', '.', ',') // "-1.000,12"
```

## API

### commaNumber(number, [separator=','])
### commaNumber(number, [separator=','], [decimalChar='.'])

**Parameters:**

* number : {(Number|String)} Number to format
* separator : {String} Value used to separate numbers
* decimalChar : {String} Value used to separate the decimal value

**Returns:**

Expand Down
45 changes: 45 additions & 0 deletions benchmark/original.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Comma number formatter
* @param {Number} number Number to format
* @param {String} [separator=','] Value used to separate numbers
* @returns {String} Comma formatted number
*/
module.exports = function commaNumber (number, separator) {
separator = typeof separator === 'undefined' ? ',' : ('' + separator)

// Convert to number if it's a non-numeric value
if (typeof number !== 'number') {
number = Number(number)
}

// NaN => 0
if (isNaN(number)) {
number = 0
}

// Return Infinity immediately
if (!isFinite(number)) {
return '' + number
}

var stringNumber = ('' + Math.abs(number))
.split('')
.reverse()

var result = []
for (var i = 0; i < stringNumber.length; i++) {
if (i && i % 3 === 0) {
result.push(separator)
}
result.push(stringNumber[i])
}

// Handle negative numbers
if (number < 0) {
result.push('-')
}

return result
.reverse()
.join('')
}
84 changes: 84 additions & 0 deletions benchmark/run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
require('console.table')
var comma = require('../')
, Benchmark = require('benchmark')

Benchmark.options.initCount = 10
Benchmark.options.minSamples = 10

// useful when altering things because it runs once per.
// Benchmark.options.initCount = 1
// Benchmark.options.minSamples = 1
// Benchmark.options.minTime = -1
// Benchmark.options.maxTime = -1

inputs = [
'1',
'12',
'123',
'1234',
'12345',
'123456',
'1234567',
'12345678',
'123456789',
'1234567890',
'12345678901',
'123456789012',

1,
12,
123,
1234,
12345,
123456,
1234567,
12345678,
123456789,
1234567890,
12345678901,
123456789012
]

var methods = [
require('./original'),
comma
]

var suite = new Benchmark.Suite
, headers = [' ', 'original', 'alternate']
, results = []

for (var i = 0; i < inputs.length; i++) {
var input = inputs[i]
, name = typeof input === 'string' ? '\'' + input + '\'' : input

results.push([name])

suite.add(name, methods[0].bind(null, input))
suite.add(name, methods[1].bind(null, input))
}

var columns = methods.length + 1
, row = 0

suite.on('cycle', function(event) {
var it = event.target
, which = results[row].length === 1 ? ' original' : 'alternate'

console.log(which,'completed',it.name)

results[row].push(comma(it.hz.toFixed(2)) + ' (+-' + it.stats.rme.toFixed(2) + '%)')

if (results[row].length === columns) {
return row++
}
})

suite.on('complete', function() {
console.log()
console.table(headers, results)
})

suite.run({
async: false
})
72 changes: 51 additions & 21 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,74 @@
* Comma number formatter
* @param {Number} number Number to format
* @param {String} [separator=','] Value used to separate numbers
* @param {String} [decimalChar='.'] Decimal character
* @returns {String} Comma formatted number
*/
module.exports = function commaNumber (number, separator) {
separator = typeof separator === 'undefined' ? ',' : ('' + separator)
module.exports = function commaNumber (number, separator, decimalChar) {

// Convert to number if it's a non-numeric value
// get the stringNumber based on type, or, return '0' for invalid types
var stringNumber
switch(typeof number) {
case 'string': stringNumber = number ; break
case 'number': stringNumber = String(number) ; break
default : return '0' // object, undefined, function, array, ...
}

// strip off decimal value to append to final result at the bottom
decimalChar = typeof decimalChar === 'undefined' ? '.' : String(decimalChar)
var decimal = stringNumber.lastIndexOf(decimalChar)
if (decimal > -1) {
number = stringNumber.slice(0, decimal)
decimal = stringNumber.slice(decimal)
stringNumber = number
} else {
decimal = null
}

// ensure we have an actual number
if (typeof number !== 'number') {
number = Number(number)
}

// when it doesn't need a separator then return it (w/decimal, if exists)
if (-1000 < number && number < 1000) {
return decimal ? stringNumber + decimal : stringNumber
}

// NaN => 0
if (isNaN(number)) {
number = 0
return '0'
}

// Return Infinity immediately
if (!isFinite(number)) {
return '' + number
if (!isFinite(number) ) {
return stringNumber
}

var stringNumber = ('' + Math.abs(number))
.split('')
.reverse()
// below here we split the number at spots to add a separator.
// then, combine it with the separator and add decimal value (if exists)

var start = stringNumber[0] === '-' ? 1 : 0 // start after minus sign
, count = stringNumber.length - start - 1 // count digits after first
, strings = [] // hold string parts
, i = (count % 3) + 1 + start // index for first separator

var result = []
for (var i = 0; i < stringNumber.length; i++) {
if (i && i % 3 === 0) {
result.push(separator)
}
result.push(stringNumber[i])
// grab string content before where the first separator belongs
strings.push(stringNumber.slice(0, i))

// split remaining string in groups of 3 where a separator belongs
for (; i < stringNumber.length; i += 3) {
strings.push(stringNumber.substr(i, 3))
}

// Handle negative numbers
if (number < 0) {
result.push('-')
// finally, combine groups with the separator
separator = typeof separator === 'undefined' ? ',' : String(separator)
stringNumber = strings.join(separator)

// if there's a decimal value then append it
if (decimal) {
stringNumber += decimal
}

return result
.reverse()
.join('')
return stringNumber
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
},
"homepage": "https://github.com/cesarandreu/comma-number#readme",
"devDependencies": {
"benchmark": "^2.1.2",
"console.table": "^0.7.0",
"standard": "^4.5.4",
"tape": "^4.0.0"
}
Expand Down
Loading