I'm trying to write a function that takes some object, for example a number, a string, a list, or a map (of key-value pairs); and returns a valid JSON representation of that input as a string.
I have already set up other json encoders for simple numbers and string inputs:
Input => Output
a number with value 123 => 123 (string)
a string with value abc => "abc" (string)
But I'm having issues converting an array such as [1,"2",3]
Input => Output
1,2,three array => [1,2,"three"] (string)
Here is my current code:
var my_json_encode = function(input) {
if(typeof(input) === "string"){
return '"'+input+'"'
}
if(typeof(input) === "number"){
return `${input}`
}
//This is causing my issue
if(Array.isArray(input)) {
console.log(input)
}
I could simply add and return JSON.stringify(input) to change it but I don't want to use that.
I know I can create some sort recursive solution as I have base cases set up for numbers and strings. I'm blocked on this and any help will be appreciated
Edit: So the solution as been provided below in the answers section! Thanks :)
For arrays take a recursive approach with the items.
const
json_encode = (input) => {
if (typeof input === "string") return `"${input}"`;
if (typeof input === "number") return `${input}`;
if (Array.isArray(input)) return `[${input.map(json_encode)}]`;
};
console.log(json_encode([1, 'foo', [2, 3]]));
console.log(JSON.parse(json_encode([1, 'foo', [2, 3]])));
You already have the function that converts scalar values to json values.
So, you can call this function for all array's member (e.g. using https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and then join it (https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/join) and add '[' and ']' to the resulting string
PS: this approach will work also in situations when you have an array of arrays
Example of the implementation:
var my_json_encode = function(input) {
if(typeof(input) === "string"){
return '"'+input+'"'
}
if(typeof(input) === "number"){
return `${input}`
}
if(Array.isArray(input)) {
const formatedArrayMembers = input.map(value => my_json_encode(value)).join(',');
return `[${formatedArrayMembers}]`;
}
}
How to work out which variable has the most characters.
For example :
var one = "qwert";
var two = "qwertyu"
var three ="qwertyuiop";
How to work out which variable has the most character.
First thing I am doing is counting the number of characters in each string.
var onelength = one.length;
var twolength = two.length;
var threelength = three.length;
The part I am struggling on is javascript to work out which of the above lengths has the most characters.
There's really no way to do this in Javascript (nor indeed in most languages).
What you're asking for is a kind of reflection. Conceptually, a function nameOfVariable that takes a variable and gives you it's string name in return:
nameOfVariable(one): 'one'
Not possible.
The answers above are attempts to work around that. Ultimately in real code this would be structured not as a bag of variables but as an object (which is kinda like a bag of variables, except you can recover the names)
const strings = {
one: 'abcde',
two: 'abcdef',
three: 'abcd',
};
// Return key in object corresponding to longest string,
// or null if object is empty.
const longest_string = strings => {
let max = null;
for (let name in strings) {
if (max === null || strings[name].length > strings[max].length) {
max = name;
}
}
return max;
}
console.log(longest_string(strings));
try
[one,two,three].reduce((a,c) => a.length>c.length? a:c,'');
var one = "qwert";
var two = "qwertyu";
var three ="qwertyuiop";
let r= [one,two,three].reduce((a,c) => a.length>c.length? a:c,'');
let v= Object.entries({one,two,three}).reduce((a,c) => a[1].length>c[1].length ? a:c,['','']);
console.log('longest variable:', v[0], '=', r);
var words=['ape','parrot','elephant'];
console.log( longestWord( words ) );
function longestWord( words ){
var longest = '';
words.forEach(function(element){
if(longest.length < element.length)
longest = element;
});
return longest;
}
You don't need to use JQuery for this. If you save the strings in an array:
const a = ["qwert","qwertadf","qwertfasdf"]
you can use this (using ES2015 features):
let max_length = Math.max(...a.map(e=>e.length))
If you want to know the greater element, you can use this:
a.findIndex(e => e.length === ml)
Just do Math.max();
Example:
Math.max(onelength, twolength, threelength);
This will return the highest value.
I have one rest call that gives me information from query parameters and I need to determine whether they are a string or an int, array, boolean.
For example, if I have:
/.../something?id=1
I'll receive '1', but I know that's an integer.
Furthermore, I have:
/.../something?id=[1,2,3]
I'll receive '[1,2,3]' but I know it's an array. Finally, if I have:
/.../something?id=string
I'll receive 'string' and I should use it as a regular string.
Is regex the only way of doing that check for each type?
You can use JSON.parse with a catch block.
var options = ['12', '[1,2,3]', 'string', 'false', '{"x" : 2}', '/hey/', /hey/];
var parsed = options.map(x => {
try {
return JSON.parse(x)
} catch(e) {
return x;
}
});
var types = parsed.map(x => /\[object (.*)\]$/.exec(Object.prototype.toString.call(x))[1])
console.log(types);
Once you have a value
var value = "1"; //or whatever value after `id=`
you can apply this logic
var type = "";
var isNum = ( s ) => !isNaN(s);
var isObject = ( s ) => {
try { s = JSON.parse(s); return Array.isArray(s) ? "array" : "object" } catch( e ){ return false }
};
Now use them as
type = isNum( value ) ? "number" : ( isObject( s ) || "string" );
Note
If value is a function definition, it will still return a string
One way to solve this is to use trial-and-error methodologies:
If you have the value starting from [ and ending with ], you probably can assume that its an array. Use JSON.parse to be sure.
If first case doesn't match, use /^\d+$/ to test the string against integer values. Use parseInt() to be sure.
Lastly, if above both test cases fail, you can be sure that its a string, because strings can hold almost all type of values.
Savio,
One way you can handle it is to fetch the value and use switch/case statement with 'typeof' to see what they are.
Typeof explanation on MDN
// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
// Strings
typeof 'bla' === 'string';
// Booleans
typeof true === 'boolean';
// use Array.isArray or Object.prototype.toString.call
// to differentiate regular objects from arrays
typeof [1, 2, 4] === 'object';
I have a formula and an object containing variables as a key
My object is as
{
xyz:{
v:20
},
ab:{
v:2
},
y:{
v:30
},
z:{
v:40
},
}
Now I have to evaluate the formula
Eg.
xyz+ab*(y+z)
Result : 20+2*(30+40)
Any optimized solution ?
Please note that keys are in the form of "characters..characters"
eg. ABC..XY12
Update : Actual object is
{
pnl..xyz:{
v:20
},
pxl..ab:{
v:2
},
pnl..y:{
v:30
},
pxl..z:{
v:40
},
}
and the formula is
pnl..xyz+pxl..ab*(pnl..y+pxl..z)
You can use a regex to find variable names and post that you can use eval
Sample
var data={xyz:{v:20},ab:{v:2},y:{v:30},z:{v:40},abc12:{v:12},"abc..bc":{v:31}};
function processOperation(str) {
var formula = str;
var operatios = /[+\-\*\/\(\)]/g;
var keys = formula.split(operatios);
keys.forEach(function(k) {
if (k && data[k]) formula = formula.replace(k, data[k].v)
});
console.log(formula);
return eval(formula)
}
var formula1 = "xyz+ab*(y+z)"
console.log(processOperation(formula1))
var formula2 = "xyz+ab*(y+z)-abc12"
console.log(processOperation(formula2))
var formula3 = "xyz+ab*(y+z)-12"
console.log(processOperation(formula3))
var formula4 = "xyz+ab*(y+z)-abc..bc"
console.log(processOperation(formula4))
You can write your own custom parser and evaluator, but there will be loads of edge cases, validation and operator precedence cases to be
taken care of.
I would recommend not reinventing the wheel, and using math.js , it is a lightweight dedicated library for maths in javascript.
Here is how formula evaluation can be done in a single line.
var scope = { xyz : 20, ab : 2, y : 30, z : 40 };
var answer = math.eval('xyz+ab*(y+z)', scope);
console.log('The answer is:' + answer);
<script src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/3.5.3/math.min.js"></script>
This function will replace the keys of the provided obj in the provided formula string. It's curried so you can reuse the same formula with different values for the variables.
const obj = {
xyz:{ v:20 },
ab:{ v:2 },
y:{ v:30 },
z:{ v:40 }
}
const obj2 = {
'pnl..xyz':{ v:20 },
'pxl..ab':{ v:2 },
'pnl..y':{ v:30 },
'pxl..z':{ v:40 },
}
/*
* evalFormula :: String -> {key:{v:Int}} -> String
*
* replace the formula string with the obj values
*/
const evalFormula = formula => obj => {
// get the keys
const keys = Object.keys(obj)
// sort keys by length so we replace the longer strings first
keys.sort(sortBy('length'))
// reduce the keys into the formula
return keys.reduce((str, key) =>
// replace the key with it's corresponding value each iteration
str.replace(stringToRegex(key, 'g'), obj[key].v)
, formula)
}
// get a regular expression from an input string
const stringToRegex = (str, modifiers) =>
new RegExp(str.replace(/([\.\^\$\*\+\-\?\(\)\[\]\{\}\\])/g, '\$1'), modifiers)
const sortBy = prop => (a, b) => a[prop] > b[prop] ? -1 : a[prop] < b[prop] ? 1 : 0
// this is the executable function
const execFormula = evalFormula('xyz+ab*(y+z)')
const otherFormula = evalFormula('pnl..xyz+pxl..ab*(pnl..y+pxl..z)')
console.log(
execFormula(obj),
otherFormula(obj2)
)
Edit.
You would just need to add in a little escaping for the illegal characters in your keys, then create a new formula and pass in the new obj
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);