I need to parse querystrings that contain both text and numbers. For example the following querystring:
?userID=12&team=Sales&quarter=Q1&count=2310
should be translated into the following JavaScript object:
{
userID:12, // not "12"
team:"Sales",
quarter:"Q1",
count:2310 // not "2310"
}
Currently I am doing it in two steps:
Parse the querystring
Go through all the parameters and identify which ones are numbers (either with a regex or an isNumber function !isNaN(parseFloat(n)) && isFinite(n)
This seems rather inefficient especially as most of my parameters are not numbers. Is there a better way?
do you know where are you going to use the specify value?
Because if you multiplying any string in number format like "3239" by 1 this will convert that string in number..
var example = 5 + (o.count*1) //o.count will be a number...
Two suggestions:
If you know which parameters are going to hold numbers, only do the conversion for those
The fastest way to convert strings to numbers as far as I know is to use the unary operator on them, as follows:
+(strVar)
Also multiplying by 1 is supposed to be fast AFAIK
After you parse the querystring you can convert those string representations of integer value to an actual integer like this:
var obj; // your object that the string is parsed into, with all values as strings.
for (var prop in obj) {
if (String(parseInt(obj[prop])) === obj[prop]) {
obj[prop] = parseInt(obj[prop]);
}
}
Related
I am streaming data from a CSV file and I am pushing certain values to an array. Some of these values are very large, and may be exported as exponential values (e.g. 5.02041E+12) and some may be normal values.
I'd like to have an if statement that checks to see if these values are exponential or not, and if they are I will pass them to a function that converts them into 'normal' numbers (e.g. 5020410000000). Is there a quick way to do this?
(These values are passed to an API call which is why they need to be converted to 'normal' values)
Example of what this may look like:
valueOne = 5.02041E+12;
valueTwo = 1234;
if (valueOne.isExponential) {
**pass to converting function**
}
//Output = 5020410000000
if (valueTwo.isExponential) {
**pass to converting function**
}
//Output = 1234 (unchanged)
I'd expect all values in the array to therefore be 'normal' values (i.e. NOT is exponential form)
Numbers are numbers, the values 5.02041E+12 and 5020410000000 do not differ internally:
// values in code:
var withe=5.02041E+12;
var withoute=5020410000000;
console.log(withe,"?=",withoute,withe===withoute);
// values parsed from strings:
var stringwithe="5.02041E+12";
var stringwithoute="5020410000000";
var a=parseFloat(stringwithe);
var b=parseFloat(stringwithoute);
console.log(a,"?=",b,a===b);
And you can also see that when you simply display a number, it will not use the scientific notation by default, actually you would have to ask for it via using toExponential()
One thing you can worry about is the internal precision of Number. It has a method isSafeInteger() and various fields, like MAX_SAFE_INTEGER. Surpassing that value can lead to unexpected results:
var a=Number.MAX_SAFE_INTEGER;
console.log("This is safe:",a,Number.isSafeInteger(a));
a++;
for(var i=0;i<5;i++)
console.log("These are not:",a++,Number.isSafeInteger(a));
So the loop can not increment a any further, because there is no such number as 9007199254740993 here. The next number which exists after 9007199254740992 is 9007199254740994. But these numbers are more than 1000x greater than the 5020410000000 in the question.
You can just use toPrecision on every number and ensure it converts
const valueOne = 5.02041E+12;
const valueTwo = 1234;
const precisionValueOne = valueOne.toPrecision(); // "5020410000000"
const precisionValue2 = valueTwo.toPrecision(); // "1234"
You can then, optionally convert it back to numbers:
sanitizedValueOne = Number(precisionValueOne); // 5020410000000
sanitizedValueTwo = Number(precisionValueTwo); // 1234
Do a RegExp match for E+ and probably for E-
The 'number' you are starting with must be text, but you should do a bit of sanity checking too.
Might be a good idea to check whether it is larger than MaxInt before you try any Math-based conversions.
I'm calling JSON.parse() to parse a JSON string which has small decimals.
The precision of the decimals is not being maintained after parsing. For example, a value like 3.1e-7 is being returned instead of the actual decimal.
How can I deserialize a JSON string in ng2+ while maintaining decimal precision?
UPDATE
I was thinking about mapping out the values from the string and then setting the values manually to the object after JSON.parse() but when I set a different small decimal number as a property value, the same number formatting occurs. So is this problem not necessarily unique to JSON.parse() but to Javascript in general? Or does JSON.parse() somehow configure property types in a fixed way?
As soon as you pass your JSON string through JSON.parse, you'll lose precision because of the way floating point math works. You'll need to store the number as an object designed for storing arbitrary-precision numbers, and you'll need to fiddle with the string itself before parsing it. The simplest way is with regexes. JSON is a context free grammar, and regexes work on regular grammars, so the warning applies:
WARNING: PARSING CFG WITH REGEX MAY SUMMON ZALGO
This regex should turn the numbers in your JSON into strings:
let stringedJSON = origJSON.replace(/:\s*([-+Ee0-9.]+)/g, ': "uniqueprefix$1"');
But I haven't tested it extensively and it definitely will screw things up if you have keys that are something like data:42.
Assuming it worked correctly, stringedJSON should now be something like {"foo": "uniqueprefix0.00000017", "bar": "an actual string"}. You can parse this with JSON.parse without losing precision, but uniqueprefix0.00000017 isn't what you want. JSON.parse can be called with an extra reviver argument, which transforms values passed to it before returning them. You can use this to convert your data back into a useful form:
let o = JSON.parse(stringedJSON, (key, value) => {
// only changing strings
if (typeof value !== 'string') return value;
// only changing number strings
if (!value.startsWith('uniqueprefix')) return value;
// chop off the prefix
value = value.slice('uniqueprefix'.length);
// pick your favorite arbitrary-precision library
return new Big(value);
});
This seems to work, on an array of strings that look like numbers (they're numbers from a CSV file read in with csv-parse, which seems to convert everything into strings):
var a = ['123.1', '1234.0', '97.43', '5678'];
Math.max.apply(Math, a);
Returns 5678.
Does Math.max convert strings to numbers automatically?
Or should I do a + conversion myself first to be extra safe?
Does Math.max convert strings to numbers automatically?
Quoting the ECMA Script 5.1 Specification for Math.max,
Given zero or more arguments, calls ToNumber on each of the arguments and returns the largest of the resulting values.
So, internally all the values are tried to convert to a number before finding the max value and you don't have to explicitly convert the strings to numbers.
But watch out for the NaN results if the string is not a valid number. For example, if the array had one invalid string like this
var a = ['123.1', '1234.0', '97.43', '5678', 'thefourtheye'];
console.log(Math.max.apply(Math, a));
// NaN
You'll get a NaN if any of the strings aren't numbers, but otherwise it should work fine. I'd add the + just to be safe.
Consider this situation:
<script>
var a=['123.1', '1234.0', '97.43', '5678','0 11111111'];
console.log(Math.max.apply(Math, a));
</script>
You need to cast elements from array to be extra safe..
if you intend to check for the max element in an array of strings using Math.max() method. you can compare the length of reach element
question: var a = ['123.1', '1234.0', '97.43', '5678'];
const checkLength = Math.max.apply(null, a.map(element => element.length));
or using spread operator for shorter form
const checkLength = Math.max(...a.map(element => element.length));
then filter to get all the elements
a.filter(elem => elem.length === checkLength)
All I want to do is to create a JSON string like this :
'{ "a" : 1.00 }'
I have tried
var n = 1.00;
var x = { a : n };
console.log(JSON.stringify(x)); // Gives {"a":1}
var n = 1.00;
var x = { a : n.toFixed(2) };
console.log(JSON.stringify(x)); // Gives {"a":"1.00"}
var x = { x : 1.00 };
x = JSON.stringify(x , function(key,val ){
if( typeof val === "number")
return val.toFixed(2);
return val;
});
console.log(x); // Gives {"x":"1.00"}
Is it even possible to represent '{ "a" : 1.00 }' as a JSON string in javascript ?
If yes, how can I do it ?
A number in JSON doesn't have any specific precision. A number is represented as the shortest notation that is needed to reproduce it.
The value 1.00 is the same as the value 1, so that is how it is represented in JSON.
If you specifically want to represent a number in the 1.00 format, then you can't store it as a number, you would need to use a string.
The string '{"x":1.00}' is valid JSON, but it has the same meaning as '{"x":1}'.
toFixed() returns a string, and therefore will always result in "1.00" instead of 1.00.
The only way I can think of to get a JSON string with 1.00 as a value is to create it like you did above with toFixed(), then modify the string afterwards by either removing the quote characters from "1.00".
You could also create it without toFixed() and then go in and add the .00 characters.
Either way it strikes me as more effort than it's worth, but it should be possible. I can't think of a way to do it directly.
What you are trying to achieve is out of the scope of serialized object concept. Serialization is about presenting data in the most general way so both sender and the receiver of this serialized object will be able to understand in any programming language. The definition of this data type you are trying to represent is called 'Number' in JSON. You should parse or cast it to the type you need (this is part of the deserialization concept, and usually being done by the JSON parsing method).
Is there a way to force .getRange().getValues() to return an int? Although only numbers exist in my range, it is returning them as strings. I would like to avoid using parseInt in every one of my statements or creating a separate array with converted values.
Or is that the only solution, to get the array and then parseInt the entire array in a loop?
you can do this easily using the unary '+' operator as follows:
First get your values from your spreadsheet using getValue() or getValues(). Suppose you get two such values, and store them in A = 1 and B = 2. You can force them to be recognized as numbers by using any math binary operator except for +, which concatenates strings, so A - B = -1, while A + B will return '12'.
You can force the variables to be numbers simply by using the + unary operator with any variable that might be interpreted as a string. For example, +A + +B will return the correct value of 3.
You can use parseInt() or Number()
example
var A='12';var B=5
A+B = 125
parseInt(A)+B = 17
Number(A)+B = 17
That said, getValues() is not supposed to return strings unless values have some space or other non-numeric characters in it... are these values entered manually or come as a result of some function ?
getValues() returns a 2D array of Objects - so these are Strings, Integers or Date objects depending on what these are formatted as in your spreadsheet.
Go back to your spreadsheet and see what the cells that have integer values are formatted as. Format them as integers and you should get back integers.