shek
shek

Reputation: 297

Convert specific json elements to number in json

I have the following json object:

[{
    "WEIGHTED_ARR_LAST_SLP": "0.03801186624130076",
    "SLIPPAGE_INTERVAL_VWAP_BPS": "10.2711",
    "ROOT_ORDER_ID": "735422197553491",
    "ARRIVAL_MID_PX": "93.6100",
    "WEIGHTED_ARR_SLP": "0.12323190317127024",
    "AVG_PX": "93.6586",
    "LEAVES_QTY": "0",
    "WEIGHT": "0.02372627566400397",
    "PARTICIPATION_RATE": "0E-12",
    "LOCAL_REF_END_TIME": "2016-09-06 06:00:27.775",
    "WEIGHTED_IVWAP_SLP": "0.2436949499725512",
    "NOTIONAL_USD": "477940",
    "LIQ_CONSUMPTION": "15.21",
    "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",
    "IVWAP_PX": "93.5625",
    "LIMIT_PX": "93.6100",
    "ORDER_ID": "735422197553491",
    "SLIPPAGE_ARR_MID_BPS": "5.1939",
    "ORDER_QTY": "5103",
    "EXECUTION_STYLE": "2", {"ORDER_QTY": "5100", ..........}
}]

I want to coonvert only "Ord Qty", "Exec Qty", "AVG Px", "Notional", "Limit Px", "Arrival Px" "Arrival Px Slpg", "IVWAP Px Slpg", "LIQ Consumption" to Number; and then display WEIGHTED_IVWAP_SLP & WEIGHTED_ARR_SLP with 4 decimal points, instead of so many. I'm trying to do it in the following way:

var jsondata = document.getElementById("jsonArray").value;
var jsondataObj = JSON.parse(jsondata);

function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

var parsedData = jsondataObj.map(function(obj) {
    return Object.keys(obj).reduce(function(memo, key) {
        var value = obj[key];
        //console.log(value);
        memo[key] = isNumeric(value) ? Number(value).toFixed(4) : value;
        //localStorage.setItem("storeditem", value);

        return memo;
    }, {})
});

But this is converting all of fields of numbers with 4 decimal point. How to convert only specific fields?

Upvotes: 0

Views: 147

Answers (3)

trincot
trincot

Reputation: 350167

You can modify your code slightly by adding a filter on the keys, before launching the reduce(). Secondly, you could put an extra condition in your ternary operator, to deal with the two fields that should get 4 decimal digits:

var parsedData = jsondataObj.map(function(obj) {
    return Object.keys(obj).filter (
        key => ["ORDER_QTY", "EXEC_QTY", "AVG_PX", "NOTIONAL_USD", "LIMIT_PX", 
                "ARRIVAL_MID_PX", "WEIGHTED_ARR_SLP", "WEIGHTED_IVWAP_SLP", 
                "LIQ_CONSUMPTION"].includes(key)
    ).reduce(function(memo, key) {
        var value = obj[key];
        memo[key] = !isNumeric(value) ? value
             : ["WEIGHTED_IVWAP_SLP", "WEIGHTED_ARR_SLP"].includes(key) 
                 ? Number(value).toFixed(4) 
                 : Number(value);
        return memo;
    }, Object.assign({}, obj))
});

Note that you must then also pass a copy of the original object as initial value for reduce. For this Object.assign can be used.

Also, be aware that .toFixed turns a number back to string type, as this is the only way to actually ensure you see 4 decimal digits. If you want to really have the number type, then apply Number() to that result again:

Number(Number(value).toFixed(4))

Of course, trailing decimal zeroes will not display when you output such numbers without formatting.

var jsondata = `[{
    "WEIGHTED_ARR_LAST_SLP": "0.03801186624130076",
    "SLIPPAGE_INTERVAL_VWAP_BPS": "10.2711",
    "ROOT_ORDER_ID": "735422197553491",
    "ARRIVAL_MID_PX": "93.6100",
    "WEIGHTED_ARR_SLP": "0.12323190317127024",
    "AVG_PX": "93.6586",
    "LEAVES_QTY": "0",
    "WEIGHT": "0.02372627566400397",
    "PARTICIPATION_RATE": "0E-12",
    "LOCAL_REF_END_TIME": "2016-09-06 06:00:27.775",
    "WEIGHTED_IVWAP_SLP": "0.2436949499725512",
    "NOTIONAL_USD": "477940",
    "LIQ_CONSUMPTION": "15.21",
    "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",
    "IVWAP_PX": "93.5625",
    "LIMIT_PX": "93.6100",
    "ORDER_ID": "735422197553491",
    "SLIPPAGE_ARR_MID_BPS": "5.1939",
    "ORDER_QTY": "5103",
    "EXECUTION_STYLE": "2"
}]`;

var jsondataObj = JSON.parse(jsondata);

function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

var parsedData = jsondataObj.map(function(obj) {
    return Object.keys(obj).filter (
        key => ["ORDER_QTY", "EXEC_QTY", "AVG_PX", "NOTIONAL_USD", "LIMIT_PX", 
                "ARRIVAL_MID_PX", "WEIGHTED_ARR_SLP", "WEIGHTED_IVWAP_SLP", 
                "LIQ_CONSUMPTION"].includes(key)
    ).reduce(function(memo, key) {
        var value = obj[key];
        memo[key] = !isNumeric(value) ? value
             : ["WEIGHTED_IVWAP_SLP", "WEIGHTED_ARR_SLP"].includes(key) 
                 ? Number(value).toFixed(4) 
                 : Number(value);
        return memo;
    }, Object.assign({}, obj))
});

console.log(parsedData);

Upvotes: 1

TylerY86
TylerY86

Reputation: 3792

This is kind of doing your job for you right? Well, this answer doesn't use your code, but you should be able to apply it just the same. This uses language constructs such as if, for and for ... in as opposed to methods of Array like map, reduce, and filter.

var a = [{
  "WEIGHTED_ARR_LAST_SLP": "0.03801186624130076",
  "SLIPPAGE_INTERVAL_VWAP_BPS": "10.2711",
  "ROOT_ORDER_ID": "735422197553491",
  "ARRIVAL_MID_PX": "93.6100",
  "WEIGHTED_ARR_SLP": "0.12323190317127024",
  "AVG_PX": "93.6586",
  "LEAVES_QTY": "0",
  "WEIGHT": "0.02372627566400397",
  "PARTICIPATION_RATE": "0E-12",
  "LOCAL_REF_END_TIME": "2016-09-06 06:00:27.775",
  "WEIGHTED_IVWAP_SLP": "0.2436949499725512",
  "NOTIONAL_USD": "477940",
  "LIQ_CONSUMPTION": "15.21",
  "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",
  "IVWAP_PX": "93.5625",
  "LIMIT_PX": "93.6100",
  "ORDER_ID": "735422197553491",
  "SLIPPAGE_ARR_MID_BPS": "5.1939",
  "ORDER_QTY": "5103",
  "EXECUTION_STYLE": "2"
}];
var fieldsToConvertToNumbers = [
  "ORDER_QTY", "EXEC_QTY", "AVG_PX",
  "NOTIONAL_USD", "LIMIT_PX", "ARRIVAL_MID_PX",
  "WEIGHTED_IVWAP_SLP", "LIQ_CONSUMPTION"
];
for (var i = 0; i < a.length; ++i) {
  var b = a[i];
  for (var j = 0; j < fieldsToConvertToNumbers.length; ++j) {
    var field = fieldsToConvertToNumbers[j];
    if (field in b) {
      var value = parseFloat(b[field]);
      if (!isNaN(value))
        b[field] = value;
    }
  }
}
var pre = document.createElement("pre");
pre.appendChild(document.createTextNode(JSON.stringify(a, null, ' ')));
document.body.appendChild(pre);

Use parseFloat to convert the values to numbers, but be sure to check for NaN results before deciding to update the value. Use IsNaN for that. Don't think you really need to use !IsFinite, but knock yourself out.

So now you want to use toFixed to fix your string display.

var text = (3.1415926535897932384626433832795028841971).toFixed(4);
var pre = document.createElement("pre");
pre.appendChild(document.createTextNode(text));
document.body.appendChild(pre);

So now you can use toFixed to convert your numbers to strings that have only 4 decimal places of precision. However, they are strings instead of numbers. So you have to parse them back using parseFloat.

var a = [{
  "WEIGHTED_ARR_LAST_SLP": "0.03801186624130076",
  "SLIPPAGE_INTERVAL_VWAP_BPS": "10.2711",
  "ROOT_ORDER_ID": "735422197553491",
  "ARRIVAL_MID_PX": "93.6100",
  "WEIGHTED_ARR_SLP": "0.12323190317127024",
  "AVG_PX": "93.6586",
  "LEAVES_QTY": "0",
  "WEIGHT": "0.02372627566400397",
  "PARTICIPATION_RATE": "0E-12",
  "LOCAL_REF_END_TIME": "2016-09-06 06:00:27.775",
  "WEIGHTED_IVWAP_SLP": "0.2436949499725512",
  "NOTIONAL_USD": "477940",
  "LIQ_CONSUMPTION": "15.21",
  "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",
  "IVWAP_PX": "93.5625",
  "LIMIT_PX": "93.6100",
  "ORDER_ID": "735422197553491",
  "SLIPPAGE_ARR_MID_BPS": "5.1939",
  "ORDER_QTY": "5103",
  "EXECUTION_STYLE": "2"
}];
var fieldsToConvertToNumbers = [
  "ORDER_QTY", "EXEC_QTY", "AVG_PX",
  "NOTIONAL_USD", "LIMIT_PX", "ARRIVAL_MID_PX",
  "LIQ_CONSUMPTION"
];
var fieldsToConvertToFixedNumbers = [
  "WEIGHTED_IVWAP_SLP", "WEIGHTED_ARR_SLP"
];
for (var i = 0; i < a.length; ++i) {
  var b = a[i];
  for (var j = 0; j < fieldsToConvertToNumbers.length; ++j) {
    var field = fieldsToConvertToNumbers[j];
    if (field in b) {
      var value = parseFloat(b[field]);
      if (!isNaN(value))
        b[field] = value;
    }
  }
  for (var j = 0; j < fieldsToConvertToFixedNumbers.length; ++j) {
    var field = fieldsToConvertToFixedNumbers[j];
    if (field in b) {
      var value = parseFloat(b[field]);
      if (!isNaN(value))
        b[field] = parseFloat(value.toFixed(4));
    }
  }
}
var pre = document.createElement("pre");
pre.appendChild(document.createTextNode(JSON.stringify(a, null, ' ')));
document.body.appendChild(pre);

So now only the specific fields have 4 decimal places. And they're numbers, not strings.

Upvotes: 1

yBrodsky
yBrodsky

Reputation: 5041

Here you have a practical example:

var x = {
    a: '1.11111',
  b: '2.22222',
  c: '3.33333',
  d: '4.444444',
  e: '5.55555'
}

var y = ['a', 'd'];

for(key in x) {
    if(y.indexOf(key) != -1) {
    x[key] = Number(x[key]).toFixed(2);
  }
}

console.log(x);

X is your object and Y is an array containing the list of keys you want to convert to fixed, or whatever you want to do. When going through the keys, if the key is inside that array, you do your thing.

https://jsfiddle.net/dtuLxzy6/

Upvotes: 0

Related Questions