How to parse a JSONArray and convert in Javascript - javascript

I have a JSONArray in this format:
[
{"COMPLIANCE_ID":"1/FIRST/US/191CC2/20160906/pW1WSpD/1","TOLERANCE":null,"WEIGHTED_ARR_LAST_SLP":"0.03801186624130076","SLIPPAGE_INTERVAL_VWAP_BPS":"10.2711","ROOT_ORDER_ID":"735422197553491","ENTERING_TRADER":"duffy_dma2","SECURITY_ID":"EOG.N","ARRIVAL_MID_PX":"93.6100","WEIGHTED_ARR_SLP":"0.12323190317127024","AVG_PX":"93.6586","ORDER_CCY":"USD","LEAVES_QTY":"0","WEIGHT":"0.02372627566400397","INITIATING_TRADER":null,"PARTICIPATION_RATE":"0E-12","LOCAL_REF_END_TIME":"2016-09-06 06:00:27.775","WEIGHTED_IVWAP_SLP":"0.2436949499725512","NOTIONAL_USD":"477940","LIST_ID":null,"SYM":"EOG","LIQ_CONSUMPTION":"15.21","URGENCY":null,"SIDE":"Sell Short","ALGO":"Hydra","EXECUTING_TRADER":"duffy_dma2","EXEC_QTY":"5103","CL_ORD_ID":"7245294057012908344","LOCAL_REF_START_TIME":"2016-09-06 05:59:57.844","SLIPPAGE_END_LAST_ARR_LAST_BPS":"1.6021","ORD_STATUS":"Filled","IVWAP_PX":"93.5625","LIMIT_PX":"93.6100","ORDER_ID":"735422197553491","VOLUME_LIMIT":"0E-12","SLIPPAGE_ARR_MID_BPS":"5.1939","ORDER_QTY":"5103","CLIENT_ACRONYM":"PEAKM","EXECUTION_STYLE":"2"},{"COMPLIANCE_ID":"1/FIRST/US/191CC2/20160906/pW1PUxP/1","TOLERANCE":null,"WEIGHTED_ARR_LAST_SLP":"-0.046488357264395964","SLIPPAGE_INTERVAL_VWAP_BPS":"0.1625","ROOT_ORDER_ID":"73855219760798","ENTERING_TRADER":"duffy_dma2","SECURITY_ID":"MCD.N","ARRIVAL_MID_PX":"118.0950","WEIGHTED_ARR_SLP":"-0.0041198933937856425","AVG_PX":"118.0923","ORDER_CCY":"USD","LEAVES_QTY":"0","WEIGHT":"0.01830250285999841","INITIATING_TRADER":null,"PARTICIPATION_RATE":"0E-12","LOCAL_REF_END_TIME":"2016-09-06 05:32:24.895","WEIGHTED_IVWAP_SLP":"0.002974156714749742","NOTIONAL_USD":"368684","LIST_ID":null,"SYM":"MCD","LIQ_CONSUMPTION":"62.82","URGENCY":null,"SIDE":"Sell","ALGO":"Hydra","EXECUTING_TRADER":"duffy_dma2","EXEC_QTY":"3122","CL_ORD_ID":"7244573979975932119","LOCAL_REF_START_TIME":"2016-09-06 05:32:19.697","SLIPPAGE_END_LAST_ARR_LAST_BPS":"-2.5400","ORD_STATUS":"Filled","IVWAP_PX":"118.0904","LIMIT_PX":"117.9900","ORDER_ID":"73855219760798","VOLUME_LIMIT":"0E-12","SLIPPAGE_ARR_MID_BPS":"-0.2251","ORDER_QTY":"3122","CLIENT_ACRONYM":"PEAKM","EXECUTION_STYLE":"4"}]
Here all the integers like "93.6585" etc. appear as strings. Is it possible to convert the integers/floats to their originate type (i.e., integer/float)?
Background information: I'm using this JSONArray in Javascript and then want to do sorting on each column, but because those appear as strings, sorting is not happening properly.
This is how I need the json columns in javascript. So, where do I add parseInt or Number for the field ORDER QTY(say)?

In order to convert all numeric values this will suffuce:
var data = [{"COMPLIANCE_ID":"1/FIRST/US/191CC2/20160906/pW1WSpD/1","TOLERANCE":null,"WEIGHTED_ARR_LAST_SLP":"0.03801186624130076","SLIPPAGE_INTERVAL_VWAP_BPS":"10.2711","ROOT_ORDER_ID":"735422197553491","ENTERING_TRADER":"duffy_dma2","SECURITY_ID":"EOG.N","ARRIVAL_MID_PX":"93.6100","WEIGHTED_ARR_SLP":"0.12323190317127024","AVG_PX":"93.6586","ORDER_CCY":"USD","LEAVES_QTY":"0","WEIGHT":"0.02372627566400397","INITIATING_TRADER":null,"PARTICIPATION_RATE":"0E-12","LOCAL_REF_END_TIME":"2016-09-06 06:00:27.775","WEIGHTED_IVWAP_SLP":"0.2436949499725512","NOTIONAL_USD":"477940","LIST_ID":null,"SYM":"EOG","LIQ_CONSUMPTION":"15.21","URGENCY":null,"SIDE":"Sell Short","ALGO":"Hydra","EXECUTING_TRADER":"duffy_dma2","EXEC_QTY":"5103","CL_ORD_ID":"7245294057012908344","LOCAL_REF_START_TIME":"2016-09-06 05:59:57.844","SLIPPAGE_END_LAST_ARR_LAST_BPS":"1.6021","ORD_STATUS":"Filled","IVWAP_PX":"93.5625","LIMIT_PX":"93.6100","ORDER_ID":"735422197553491","VOLUME_LIMIT":"0E-12","SLIPPAGE_ARR_MID_BPS":"5.1939","ORDER_QTY":"5103","CLIENT_ACRONYM":"PEAKM","EXECUTION_STYLE":"2"},{"COMPLIANCE_ID":"1/FIRST/US/191CC2/20160906/pW1PUxP/1","TOLERANCE":null,"WEIGHTED_ARR_LAST_SLP":"-0.046488357264395964","SLIPPAGE_INTERVAL_VWAP_BPS":"0.1625","ROOT_ORDER_ID":"73855219760798","ENTERING_TRADER":"duffy_dma2","SECURITY_ID":"MCD.N","ARRIVAL_MID_PX":"118.0950","WEIGHTED_ARR_SLP":"-0.0041198933937856425","AVG_PX":"118.0923","ORDER_CCY":"USD","LEAVES_QTY":"0","WEIGHT":"0.01830250285999841","INITIATING_TRADER":null,"PARTICIPATION_RATE":"0E-12","LOCAL_REF_END_TIME":"2016-09-06 05:32:24.895","WEIGHTED_IVWAP_SLP":"0.002974156714749742","NOTIONAL_USD":"368684","LIST_ID":null,"SYM":"MCD","LIQ_CONSUMPTION":"62.82","URGENCY":null,"SIDE":"Sell","ALGO":"Hydra","EXECUTING_TRADER":"duffy_dma2","EXEC_QTY":"3122","CL_ORD_ID":"7244573979975932119","LOCAL_REF_START_TIME":"2016-09-06 05:32:19.697","SLIPPAGE_END_LAST_ARR_LAST_BPS":"-2.5400","ORD_STATUS":"Filled","IVWAP_PX":"118.0904","LIMIT_PX":"117.9900","ORDER_ID":"73855219760798","VOLUME_LIMIT":"0E-12","SLIPPAGE_ARR_MID_BPS":"-0.2251","ORDER_QTY":"3122","CLIENT_ACRONYM":"PEAKM","EXECUTION_STYLE":"4"}]
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
var parsedData = data.map(function(obj) {
return Object.keys(obj).reduce(function(memo, key) {
var value = obj[key];
memo[key] = isNumeric(value) ? Number(value) : value;
return memo;
}, {})
})
console.log(parsedData);
isNumeric() - The implementation is taken from here because it is a robust way of figuring out if data is numeric or not including detecting negative numbers and floating points, among others.
Alternative one can be used but beware getting false positives or negatives.
Array.map() will iterate through the array and convert each object
Object.keys() extracts all the keys from the object
Array.reduce() finally transforms that array into a new object converting any value it encounters that looks numeric. Note the {} passed at the very end of the call - reduce(func, {}) - that is important, as it's the initial value used for the reduction function.

You can convert strings to integers and floats by doing:
parseFloat("1231.123");
parseInt("12");
Number("123");
Number("123.12");
Sources:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt

Try and run it I am not sure that this is what you want but every value now is changed, and also make some tests my be I had made some mistakes.
var data =[{"COMPLIANCE_ID":"1/FIRST/US/191CC2/20160906/pW1WSpD/1","TOLERANCE":null,"WEIGHTED_ARR_LAST_SLP":"0.03801186624130076","SLIPPAGE_INTERVAL_VWAP_BPS":"10.2711","ROOT_ORDER_ID":"735422197553491","ENTERING_TRADER":"duffy_dma2","SECURITY_ID":"EOG.N","ARRIVAL_MID_PX":"93.6100","WEIGHTED_ARR_SLP":"0.12323190317127024","AVG_PX":"93.6586","ORDER_CCY":"USD","LEAVES_QTY":"0","WEIGHT":"0.02372627566400397","INITIATING_TRADER":null,"PARTICIPATION_RATE":"0E-12","LOCAL_REF_END_TIME":"2016-09-06 06:00:27.775","WEIGHTED_IVWAP_SLP":"0.2436949499725512","NOTIONAL_USD":"477940","LIST_ID":null,"SYM":"EOG","LIQ_CONSUMPTION":"15.21","URGENCY":null,"SIDE":"Sell Short","ALGO":"Hydra","EXECUTING_TRADER":"duffy_dma2","EXEC_QTY":"5103","CL_ORD_ID":"7245294057012908344","LOCAL_REF_START_TIME":"2016-09-06 05:59:57.844","SLIPPAGE_END_LAST_ARR_LAST_BPS":"1.6021","ORD_STATUS":"Filled","IVWAP_PX":"93.5625","LIMIT_PX":"93.6100","ORDER_ID":"735422197553491","VOLUME_LIMIT":"0E-12","SLIPPAGE_ARR_MID_BPS":"5.1939","ORDER_QTY":"5103","CLIENT_ACRONYM":"PEAKM","EXECUTION_STYLE":"2"},{"COMPLIANCE_ID":"1/FIRST/US/191CC2/20160906/pW1PUxP/1","TOLERANCE":null,"WEIGHTED_ARR_LAST_SLP":"-0.046488357264395964","SLIPPAGE_INTERVAL_VWAP_BPS":"0.1625","ROOT_ORDER_ID":"73855219760798","ENTERING_TRADER":"duffy_dma2","SECURITY_ID":"MCD.N","ARRIVAL_MID_PX":"118.0950","WEIGHTED_ARR_SLP":"-0.0041198933937856425","AVG_PX":"118.0923","ORDER_CCY":"USD","LEAVES_QTY":"0","WEIGHT":"0.01830250285999841","INITIATING_TRADER":null,"PARTICIPATION_RATE":"0E-12","LOCAL_REF_END_TIME":"2016-09-06 05:32:24.895","WEIGHTED_IVWAP_SLP":"0.002974156714749742","NOTIONAL_USD":"368684","LIST_ID":null,"SYM":"MCD","LIQ_CONSUMPTION":"62.82","URGENCY":null,"SIDE":"Sell","ALGO":"Hydra","EXECUTING_TRADER":"duffy_dma2","EXEC_QTY":"3122","CL_ORD_ID":"7244573979975932119","LOCAL_REF_START_TIME":"2016-09-06 05:32:19.697","SLIPPAGE_END_LAST_ARR_LAST_BPS":"-2.5400","ORD_STATUS":"Filled","IVWAP_PX":"118.0904","LIMIT_PX":"117.9900","ORDER_ID":"73855219760798","VOLUME_LIMIT":"0E-12","SLIPPAGE_ARR_MID_BPS":"-0.2251","ORDER_QTY":"3122","CLIENT_ACRONYM":"PEAKM","EXECUTION_STYLE":"4"}];
function isInt(n){
if (n === null) return;
n = Number(n);
return !isNaN(n) && n % 1 === 0;
}
function isFloat(n) {
if (n === null) return;
n = Number(n);
return !isNaN(n) && n % 1 !== 0;
}
var result = data.map(function(currVal) {
for (var i = 0, keys = Object.keys(currVal), len = keys.length; i < len; i++) {
var key = keys[i];
var item = currVal[key];
isInt(item) && (currVal[key] = parseInt(item));
isFloat(item) && (currVal[key] = parseFloat(item));
}
return currVal;
});
console.log(result);

Related

Is there a way to determine rather my object method is a function or not

I have a function that iterates through an array of objects and returns a template literal that grabs a property value (name) and also a property value that is a function method (this is .move / how many steps they will take) The .move method uses math.random to pick a random number of steps and return that value. However, in some objects the move property is defined as an integer such as 1 or 2 instead of a random number.
Is there a way to change my fitnessTest function so that it will accept both the .move() and .move?
I tried using an if else statement inside of my while statement saying
while (steps <= 20) {
if (typeof arrayObject == function) {
steps += arrayObject[i].move();
turns++;
} else
steps += arrayObject[i].move;
turns++;
which returns the objects who have .move values defined as integers correctly but then doesnt return random numbers for the objects who have .move().
function fitnessTest(arrayObject){
let turnsArray = [];
for (i = 0; i < arrayObject.length; i++){
let steps = 0;
let turns = 0;
while (steps <= 20){
steps += arrayObject[i].move();
turns++;
} turnsArray.push(`${arrayObject[i].name} took ${turns} turns to take 20 steps.` );
} return turnsArray;
}
Right now, the function will iterate through an array of objects who have .move() as a function that generates a random number and return the proper string, but the objects who have .move set as an integer it will just give me a
type error of arrayObject[i].move is not a function
1.typeof returns a string value, you need to compare against a string of JavaScript types.
2.
You should test if the property move of a single item of arrayObject is a function, not arrayObject itself:
typeof arrayObject[i].move == 'function'
Check typeof array element but not the array variable.
var arr = [ { move: 10}, {move: function () {}} ];
console.log(typeof arr) // object
console.log(typeof arr[0].move) // number
console.log(typeof arr[1].move) // function
Change your code to :
while (steps <= 20) {
if (typeof arrayObject[i].move === "function") {
steps += arrayObject[i].move();
turns++;
} else if (typeof arrayObject[i].move === "number")
steps += arrayObject[i].move;
turns++
typeof gives you a string, so you need to equate it with a string using "". Also compare the move property and not the object itself.
You can use ternary operator for your purpose and can have a more elegant code.
while (steps <= 20) {
steps += typeof arrayObject[i].move === "function" ? arrayObject[i].move() : arrayObject[i].move;
turns++;
}

Force float value when using JSON.stringify

I want to force a Number to be a Float, after JSON.stringify(). Unfortunately JSON.stringify() deletes the 1 .0.
Example :
JSON.stringify(1.0) // "1"
Wanted outcome:
JSON.stringify(1.0) // "1.0"
I'm using an API which wants an object in JSON-Format, but it only understands decimal values. So I wanted to ask if it is possible using JSON.stringify to generate the string with decimal values without using Regex-.replace-magic
The straight and reasonably short answer to your question is no, you cannot customize the serialization of numeric values with JSON.stringify. See JSON.stringify() on MDN.
If you really need decimals for your integers you have to use "regex-magic" as you mention in your question or find a library allowing you to perform such tricks. If you aren't dealing with overly complex or many different kinds of objects you could probably stringify them manually.
As a sidenote, it sounds very, very suspicious with an API that needs to be fed with custom formatted JSON. I would tripple-check if there are any other way of using it.
Use toFixed instead of stringify. Example:
var num = 1;
var numStr = num.toFixed(1); //result is "1.0"
More about toFixed - http://www.w3schools.com/jsref/jsref_tofixed.asp.
To be clear We are talking about conversion number to string not number to float ( such type not exists in javascript ) like can be understood from question description. toFixed will always return String with specified number of decimals.
Well for anyone wondering about the regex magic here it is:
This is taken from stringify-with-floats npm library but modified to support any length of floats.
const beginFloat = "~begin~float~";
const endFloat = "~end~float~";
const stringifyWithFloats =
(config = {}, decimals = 1) =>
(inputValue, inputReplacer, space) => {
const inputReplacerIsFunction = typeof inputReplacer === "function";
let isFirstIteration = true;
const jsonReplacer = (key, val) => {
if (isFirstIteration) {
isFirstIteration = false;
return inputReplacerIsFunction ? inputReplacer(key, val) : val;
}
let value;
if (inputReplacerIsFunction) {
value = inputReplacer(key, val);
} else if (Array.isArray(inputReplacer)) {
// remove the property if it is not included in the inputReplacer array
value = inputReplacer.indexOf(key) !== -1 ? val : undefined;
} else {
value = val;
}
const forceFloat =
config[key] === "float" &&
(value || value === 0) &&
typeof value === "number" &&
!value.toString().toLowerCase().includes("e");
return forceFloat ? `${beginFloat}${value}${endFloat}` : value;
};
const json = JSON.stringify(inputValue, jsonReplacer, space);
const regexReplacer = (match, num) => {
return num.includes(".") || Number.isNaN(num)
? Number.isNaN(num)
? num
: Number(num).toFixed(decimals)
: `${num}.${"0".repeat(decimals)}`;
};
const re = new RegExp(`"${beginFloat}(.+?)${endFloat}"`, "g");
return json.replace(re, regexReplacer);
};
const test = {
test: "test",
float: 1.2,
number: 1,
};
const formatted = stringifyWithFloats(
{ float: "float", number: "float" },
2
)(test, null, 2); // null and 2 is just for pretty print
console.log(formatted);

How to check if values in one JavaScript object are present in another one?

I am trying to compare json_str1 and json_str2, here it should return true as all elements in json_str1 are present in json_str2.
For now I am doing this the long way like this
json_str1 = '{"0":"a","1":"b","2":"c"}';
json_str2 = '{"0":"c","1":"b","2":"a"}';
json_obj1 = $.parseJSON(json_str1);
json_obj2 = $.parseJSON(json_str2);
arr1 = $.map(json_obj1, function(el) { return el });
arr2 = $.map(json_obj2, function(el) { return el });
if($(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0)
alert("equal");
else
alert("not equal");
How could I make it short and simple, without converting the objects into an array ?
https://jsfiddle.net/kq9gtdr0/
Use the following code:
Object.keys(json_obj1) . every(k1 =>
Object.keys(json_obj2) . some(k2 =>
json_obj1[k1] === json_obj2[k2]
)
);
In English:
Every key k1 in json_obj1 satisfies the condition that some key k2 in json_obj2 satisifies the condition that the value of json_obj1 with key k1 is equal to the value of json_obj2 with key k2.
Or in more conversational English:
Every value in the first object matches some value in the second.
Using lodash
var _ = require('lodash');
function compareValues(jstr1, jstr2) {
return _.isEqual(_.valuesIn(JSON.parse(jstr1)).sort(), _.valuesIn(JSON.parse(jstr2)).sort());
}
json_str1 = '{"0":"a","1":"b","2":"c"}';
json_str2 = '{"0":"c","1":"b","2":"a"}';
console.log(compareValues(json_str1, json_str2));
There is short and easy accurate way to this.
You can use a third party but extremely popular utility library called Lodash. Chaining functions you can check for equality.
First parse both JSON into objects
Then use _.values() to extract the values of all keys of each into separate arrays
Find difference of two arrays. If its an empty array then both of them are equal.
You can chain all the steps into one statement like:
_.isEmpty(_.difference(_.values(json_obj1), _.values(json_obj2)))
Example: https://jsfiddle.net/kq9gtdr0/4/
For more information:
https://lodash.com/docs#values
https://lodash.com/docs#difference
https://lodash.com/docs#isEmpty
You can include the library from CDN(https://cdn.jsdelivr.net/lodash/4.5.1/lodash.min.js) or download and use it as normal script. Lodash offers plenty of useful utility functions that makes JS programming a lot easier. You better try it out.
If you prefer using libraries, then you could use underscore isMatch
_.isMatch(object, properties)
Tells you if the keys and values in properties are contained in
object.
Extending the awesome answer by #user663031, in case you need to do deep comparison, here's code that works:
export function objectOneInsideObjectTwo(jsonObj1: any, jsonObj2: any): boolean {
return Object.keys(jsonObj1).every((k1) => {
if (parseType(jsonObj1[k1]) === 'dict') {
return objectOneInsideObjectTwo(jsonObj1[k1], jsonObj2[k1]);
}
if (parseType(jsonObj1[k1]) === 'array') {
const results: boolean[] = [];
jsonObj1[k1].forEach((o: any, i: number) => {
if (parseType(o) === 'dict') {
results.push(objectOneInsideObjectTwo(o, jsonObj2[k1][i]));
} else {
results.push(o === jsonObj2[k1][i]);
}
});
return results.every((r) => r);
}
return Object.keys(jsonObj2).some((k2) => jsonObj1[k1] === jsonObj2[k2]);
});
}
export function parseType<T>(v: T): string {
if (v === null || v === undefined) {
return 'null';
}
if (typeof v === 'object') {
if (v instanceof Array) {
return 'array';
}
if (v instanceof Date) {
return 'date';
}
return 'dict';
}
return typeof v;
}
You can try this
var json_str1 = {"0":"a","1":"b","2":"c"};
var json_str2 = {"0":"c","1":"b","2":"a"};
var flag = 1;
if(Object.keys(json_str1).length == Object.keys(json_str2).length){
Object.keys(json_str1).forEach(function(x){
if(!json_str2.hasOwnProperty(x) || json_str2[x] != json_str1[x]){
flag = 0;
return;
}
});
}
if(flag)
alert('equal');
else
alert('Not Equal');
If you want to find out if both Objects have the same keys there is no way to do this without at least converting the keys of both Objects to an array with Object.keys or looping through both Objects!
The reason is simple: It's clear that you have to compare the number of keys of both Objects and the only way to do this is by looping through all properties or Object.keys.
So I think the shortest way to do this is:
json_obj1 = JSON.parse('{"0":"a","1":"b","2":"c"}');
json_obj2 = JSON.parse('{"0":"c","1":"b","2":"a"}');
keys_1 = Object.keys(json_obj1);
keys_2 = Object.keys(json_obj2);
if(keys_1.length === keys_2.length && keys_1.every(key => keys_2.indexOf(key) >= 0)) {
alert('equal')
} else {
alert('not equal')
}
If you only want to check if all keys from json1 are present in json2 you can do:
json_obj1 = JSON.parse('{"0":"a","1":"b","2":"c"}');
json_obj2 = JSON.parse('{"0":"c","1":"b","2":"a"}');
if(Object.keys(json_obj1).every(key => key in json_obj2)) {
alert('equal');
} else {
alert('not equal');
}
In your question and comments you indicate you are only looking to verify that "all elements in json_str1 are present in json_str2". Your example code doesn't just do that, it checks for the complete equality of keys by testing if all the keys (not values) in the first object are in the second object AND all the keys in the second object are in the first object. By looking at your code, i assume that when you say "elements" you mean keys.
All that aside, this might help:
// Your first few lines of code
json_str1 = '{"0":"a","1":"b","2":"c"}';
json_str2 = '{"0":"c","1":"b","2":"a"}';
json_obj1 = $.parseJSON(json_str1);
json_obj2 = $.parseJSON(json_str2);
// My new code
var values1 = Object.keys(json_obj1).map(key => json_obj1[key]);
var values2 = Object.keys(json_obj2).map(key => json_obj2[key]);
// Check if every key in the first object is in the second object.
values1.every(k1 => values2.indexOf(k1) >= 0);
// OR
// Check for equality of keys by checking both directions.
values1.every(k1 => values2.indexOf(k1) >= 0) && values2.every(k2 => values1.indexOf(k2) >= 0);
That's 2 lines to get the keys, and one line to check. You only need one of those two checks.

Array.filter numbers plus zero

I have an easy problem but i'm stuck with it: I would like to transform a list of integers and strings and returns a new list with the strings filtered out :
exemple : ([99,5,'love','hate']) == [99,5]
I used .filter but the zero are filtered as well. What would be the best option?
function filter(l) {
var arr = l.filter(Number);
return arr;
}
You can use .filter() with your own function:
function filter(l) {
var arr = l.filter(function(n) {
return typeof n === "number";
});
return arr;
}
Note that when you use the Number constructor, you'll include numbers and also any value that can successfully be converted to a number. Including such things is a little tricky, since the Number constructor always returns a number. The value might be NaN, but as it happens NaN is in fact a number, despite its intrinsic insistence that it isn't.
Try these helper functions along with Array.filter if you want to strictly filter out only integers:
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function isInt(n) {
return isNumber(n) && n % 1 === 0;
}
Try these on this fiddle
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function isInt(n) {
return isNumber(n) && n % 1 === 0;
}
var array = [99,5,'love','hate'];
var result = array.filter(function(x) {
return isInt(x);
});
document.querySelector('#output').innerHTML = JSON.stringify(result, null, 4);
Array: [99,5,'love','hate']
<br/>Result: <pre id="output"></pre>
EDIT: This has a side-effect of string-representation of integers also being returned - so [99,5,'love','hate', '23'] will return [99, 5, '23'] which is probably not what you want.

How do I write a recursive function in Javascript to add up all of the string values of a deeply nested object?

Say I have this object:
{
"prop1":"Hello",
"prop2":{
"prop1":{
"prop1":"Tablecloth",
"prop2":"Indians"
},
"prop2":"JuicyJuice"
},
"prop3":"Sponge",
"prop4":{"Bob":"Squarepants"}
}
I would like a recursive function that will return HelloTableclothIndiansJuicyJuiceSpongeSquarepants.
Whatever object I put it, I want it to cycle though until it gets all of the strings and adds them all up.
Thank you!
Here's a very simple implementation that should work for simple objects like this:
var walkProps = function(obj) {
var s = "";
for(var x in obj)
{
if(typeof obj[x] === "string")
s += obj[x];
else
s += walkProps(obj[x]);
}
return s;
}
Demonstration
Note, though, that that depends on the order in which for-in visits the properties on the object, which is not specified and can vary by engine and by how the object is constructed (for instance, the order in which the properties were added).
Update: With some slight modification, this can be used to return the values based on the alphabetical order of the keys. This method is not sensitive to implementation-dependent ordering of properties:
var walkProps = function(obj) {
var s = "", i = 0, keys = Object.keys(obj).sort(), i;
for(; i < keys.length; i++)
{
if(typeof obj[keys[i]] === "string")
s += obj[keys[i]];
else
s += walkProps(obj[keys[i]]);
}
return s;
}
So even if "prop3" comes before "prop2" it will still return the same output.
Demonstration
You would need to write a function that loops over an object's properties and see if they are a string, and then append the strings to an output. If the property is an object rather than a string, you would want to call the function on this object and append it's return value to your total output.
You can loop over an object's properties using for...in like:
var MyObject = {
'a': 'string1',
'b': 'string2'
};
for (var key in MyObject) {
var value = MyObject[key];
}
To check if a property is a string you would want to do:
typeof value === "string"
Which will return true/false accordingly.
As mentioned, for( var b in a ) may not preserve ordering:
// Return array of string values
function getStrings(a) {
if( typeof(a) == "string" ) return [a];
var list = [];
for( var b in a ) list = list.concat(getStrings(a[b]));
return list;
}
Applied to OP's data:
var a = {
"prop1":"Hello",
"prop2":{
"prop1":{
"prop1":"Tablecloth",
"prop2":"Indians"
},
"prop2":"JuicyJuice"
},
"prop3":"Sponge",
"prop4":{"Bob":"Squarepants"}
}
getStrings(a).join(); // "Hello,Tablecloth,Indians,JuicyJuice,Sponge,Squarepants"
// Or as asked for by OP (again, order is not guaranteed)
getStrings(a).join(''); // "HelloTableclothIndiansJuicyJuiceSpongeSquarepants"

Categories

Resources